@@ -172,6 +172,121 @@ namespace PeakDists
172172 }// double boost_erf_imp( double z )
173173
174174
175+ /* * 20231123: The JavaScript needed a better `erfc` implementation than just `1-erf`, or otherwise there were huge
176+ artifacts, and regions that just wouldnt draw, so wcjohns extracted this `erfc` function from boost; boost implements `erf`
177+ and `erfc` in the same function, but since the JS just needs `erfc`, wcjohns separated the erf and erf implementation, even
178+ though they are largely duplicate - saves some small amount of code/overhead.
179+ */
180+ double boost_erfc_imp ( double z )
181+ {
182+ /* Since this function is a (slight) modification of boost source code, it
183+ is subject to the Boost Version 1 Software License, whose text is:
184+
185+ Boost Software License - Version 1.0 - August 17th, 2003
186+
187+ Permission is hereby granted, free of charge, to any person or organization
188+ obtaining a copy of the software and accompanying documentation covered by
189+ this license (the "Software") to use, reproduce, display, distribute,
190+ execute, and transmit the Software, and to prepare derivative works of the
191+ Software, and to permit third-parties to whom the Software is furnished to
192+ do so, all subject to the following:
193+
194+ The copyright notices in the Software and this entire statement, including
195+ the above license grant, this restriction and the following disclaimer,
196+ must be included in all copies of the Software, in whole or in part, and
197+ all derivative works of the Software, unless such copies or derivative
198+ works are solely in the form of machine-executable object code generated by
199+ a source language processor.
200+
201+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
202+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
203+ FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
204+ SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
205+ FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
206+ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
207+ DEALINGS IN THE SOFTWARE.
208+ */
209+
210+ if ( z < 0 )
211+ return (z < -0.5 ) ? (2 - boost_erfc_imp ( -z )) : (1 + boost_erf_imp ( -z ));
212+
213+ if ( z < 0.5 )
214+ return 1 - boost_erf_imp ( z );
215+
216+ if ( z >= 28 )
217+ return 0 ;
218+
219+ if (z < 1 .5f )
220+ {
221+ static const double P[] = { -0.098090592216281240205 , 0.178114665841120341155 ,
222+ 0.191003695796775433986 , 0.0888900368967884466578 , 0.0195049001251218801359 ,
223+ 0.00180424538297014223957
224+ };
225+ static const double Q[] = { 1.0 , 1.84759070983002217845 ,
226+ 1.42628004845511324508 , 0.578052804889902404909 , 0.12385097467900864233 ,
227+ 0.0113385233577001411017 , 0.337511472483094676155e-5
228+ };
229+
230+ const double zarg = z - 0.5 ;
231+ const double P_eval = ((((zarg*P[5 ] + P[4 ])*zarg + P[3 ])*zarg + P[2 ])*zarg + P[1 ])*zarg + P[0 ];
232+ const double Q_eval = (((((Q[6 ]*zarg + Q[5 ])*zarg + Q[4 ])*zarg + Q[3 ])*zarg + Q[2 ])*zarg + Q[1 ])*zarg + Q[0 ];
233+
234+ return (0 .405935764312744140625f + P_eval / Q_eval) * (exp (-z * z) / z);
235+ }// if(z < 1.5f)
236+
237+ if ( z < 2 .5f )
238+ {
239+ static const double P[] = { -0.0243500476207698441272 , 0.0386540375035707201728 ,
240+ 0.04394818964209516296 , 0.0175679436311802092299 , 0.00323962406290842133584 ,
241+ 0.000235839115596880717416
242+ };
243+ static const double Q[] = { 1.0 , 1.53991494948552447182 , 0.982403709157920235114 ,
244+ 0.325732924782444448493 , 0.0563921837420478160373 , 0.00410369723978904575884
245+ };
246+
247+ const double zarg = z - 1.5 ;
248+ const double P_eval = ((((zarg*P[5 ] + P[4 ])*zarg + P[3 ])*zarg + P[2 ])*zarg + P[1 ])*zarg + P[0 ];
249+ const double Q_eval = ((((zarg*Q[5 ] + Q[4 ])*zarg + Q[3 ])*zarg + Q[2 ])*zarg + Q[1 ])*zarg + Q[0 ];
250+
251+ return (0 .50672817230224609375f + P_eval / Q_eval) * (exp (-z * z) / z);
252+ // Boost implementation has an additional minor error correction here
253+ }// if( z < 2.5f
254+
255+ if ( z < 4 .5f )
256+ {
257+ static const double P[] = { 0.00295276716530971662634 , 0.0137384425896355332126 ,
258+ 0.00840807615555585383007 , 0.00212825620914618649141 , 0.000250269961544794627958 ,
259+ 0.113212406648847561139e-4
260+ };
261+ static const double Q[] = { 1.0 , 1.04217814166938418171 ,
262+ 0.442597659481563127003 , 0.0958492726301061423444 , 0.0105982906484876531489 ,
263+ 0.000479411269521714493907
264+ };
265+
266+ const double zarg = z - 3.5 ;
267+ const double P_eval = ((((zarg*P[5 ] + P[4 ])*zarg + P[3 ])*zarg + P[2 ])*zarg + P[1 ])*zarg + P[0 ];
268+ const double Q_eval = ((((zarg*Q[5 ] + Q[4 ])*zarg + Q[3 ])*zarg + Q[2 ])*zarg + Q[1 ])*zarg + Q[0 ];
269+ return (0 .5405750274658203125f + P_eval / Q_eval) * (exp (-z * z) / z);
270+ // Boost implementation has an additional minor error correction here
271+ }// if( z < 4.5f )
272+
273+ static const double P[] = { 0.00628057170626964891937 , 0.0175389834052493308818 ,
274+ -0.212652252872804219852 , -0.687717681153649930619 , -2.5518551727311523996 ,
275+ -3.22729451764143718517 , -2.8175401114513378771
276+ };
277+ static const double Q[] = { 1.0 , 2.79257750980575282228 , 11.0567237927800161565 ,
278+ 15.930646027911794143 , 22.9367376522880577224 , 13.5064170191802889145 ,
279+ 5.48409182238641741584
280+ };
281+
282+ const double zarg = 1.0 / z;
283+ const double P_eval = (((((P[6 ]*zarg + P[5 ])*zarg + P[4 ])*zarg + P[3 ])*zarg + P[2 ])*zarg + P[1 ])*zarg + P[0 ];
284+ const double Q_eval = (((((Q[6 ]*zarg + Q[5 ])*zarg + Q[4 ])*zarg + Q[3 ])*zarg + Q[2 ])*zarg + Q[1 ])*zarg + Q[0 ];
285+
286+ return (0 .5579090118408203125f + P_eval / Q_eval) * (exp (-z * z) / z);
287+ // Boost implementation has an additional minor error correction here
288+ }// double boost_erfc_imp( double z )
289+
175290 /*
176291 double erf_approx( double x )
177292 {
@@ -186,11 +301,7 @@ namespace PeakDists
186301 }
187302 */
188303
189- double boost_erfc_imp ( double z )
190- {
191- return 1.0 - boost_erf_imp ( z );
192- }
193-
304+
194305 void photopeak_function_integral ( const double mean,
195306 const double sigma,
196307 const double amp,
@@ -263,7 +374,6 @@ namespace PeakDists
263374 double bortel_indefinite_integral ( const double x, const double mean,
264375 const double sigma, const double skew )
265376 {
266- const double root_two = boost::math::constants::root_two<double >();
267377 const double one_div_root_two = boost::math::constants::one_div_root_two<double >();
268378
269379 const double t = (x - mean) / sigma;
@@ -493,7 +603,7 @@ namespace PeakDists
493603 return t_eqn*sigma + mean;
494604 }
495605
496- const double root_two = boost::math::constants::root_two<double >();
606+ const double root_two = boost::math::constants::root_two<double >(); // 1.414213562373095048801688724209698078
497607 const double t_eqn = root_two* boost::math::erf_inv ( (1.0 /gauss_indef_amp) * (prob - indefinite_of_tail + gaus_indef_at_skew) );
498608 return t_eqn*sigma + mean;
499609 };// auto x_from_eqn
0 commit comments