Will, this is not true, since we could have REALLY COMPLEX function that could not be inlined.
For simple example, I have a program that computing bivariate normal probabilities, which is firstly wrote in fortran (thus source code is available in orig.rs
), It uses massive of consts which need no initialize, but fortunately, we could modify those constant for benchmark reason.
Full program is provided as follows:
src/lib.rs
pub mod orig;
pub mod r#static;
pub mod param;
src/orig.rs
/// Rust version mvbvn
/// A function for computing bivariate normal probabilities
pub fn mvbvn(mut li: f64, mut lj: f64, mut ui: f64, mut uj: f64, mut corr: f64) -> f64 {
if li >= ui || lj >= uj {
0.0
} else {
if li.abs() > ui.abs() {
(li, ui, corr) = (-ui, -li, -corr)
}
if lj.abs() > uj.abs() {
(lj, uj, corr) = (-uj, -lj, -corr)
}
// if li==f64::NEG_INFINITY {MVPHI(uj)-MVPHI(lj)}
mvbvu(li, lj, corr)
- if uj != f64::INFINITY {
mvbvu(li, uj, corr)
} else {
0.0
}
- if ui != f64::INFINITY {
mvbvu(ui, lj, corr)
} else {
0.0
}
+ if ui + uj != f64::INFINITY {
mvbvu(ui, uj, corr)
} else {
0.0
}
}
}
// // benchmark only
// fn garbage(li:f64,lj:f64,ui:f64)->f64{
// let mut ans=0.;
// for _ in 0..1000 {
// ans-=li;
// ans=ans.exp()+lj;
// ans=ans.ln()*ui;
// }
// ans
// }
// #[inline(always)]
// fn mvbvu(sh:f64,sk:f64,r:f64)->f64{
// unsafe {MVBVU(&sh,&sk,&r)}
// }
/// DOUBLE PRECISION FUNCTION MVBVU( SH, SK, R )
/// *
/// * A function for computing bivariate normal probabilities;
/// * developed using
/// * Drezner, Z. and Wesolowsky, G. O. (1989),
/// * On the Computation of the Bivariate Normal Integral,
/// * J. Stat. Comput. Simul.. 35 pp. 101-107.
/// * with extensive modications for double precisions by
/// * Alan Genz and Yihong Ge
/// * Department of Mathematics
/// * Washington State University
/// * Pullman, WA 99164-3113
/// * Email : alangenz@wsu.edu
/// *
/// * BVN - calculate the probability that X is larger than SH and Y is
/// * larger than SK.
/// *
/// * Parameters
/// *
/// * SH REAL, integration limit
/// * SK REAL, integration limit
/// * R REAL, correlation coefficient
/// * LG INTEGER, number of Gauss Rule Points and Weights
/// *
fn mvbvu(sh: f64, sk: f64, r: f64) -> f64 {
// DOUBLE PRECISION BVN, SH, SK, R, ZERO, TWOPI
// let mut bvn=0f64;
// INTEGER I, LG, NG
let lg;
let ng;
// PARAMETER ( ZERO = 0, TWOPI = 6.283185307179586D0 )
const TWOPI: f64 = 6.283185307179586;
// DOUBLE PRECISION X(10,3), W(10,3), AS, A, B, C, D, RS, XS
// DOUBLE PRECISION MVPHI, SN, ASR, H, K, BS, HS, HK
// SAVE X, W
// * Gauss Legendre Points and Weights, N = 6
// DATA ( W(I,1), X(I,1), I = 1, 3 ) /
// * 0.1713244923791705D+00,-0.9324695142031522D+00,
// * 0.3607615730481384D+00,-0.6612093864662647D+00,
// * 0.4679139345726904D+00,-0.2386191860831970D+00/
// * Gauss Legendre Points and Weights, N = 12
// DATA ( W(I,2), X(I,2), I = 1, 6 ) /
// * 0.4717533638651177D-01,-0.9815606342467191D+00,
// * 0.1069393259953183D+00,-0.9041172563704750D+00,
// * 0.1600783285433464D+00,-0.7699026741943050D+00,
// * 0.2031674267230659D+00,-0.5873179542866171D+00,
// * 0.2334925365383547D+00,-0.3678314989981802D+00,
// * 0.2491470458134029D+00,-0.1252334085114692D+00/
// * Gauss Legendre Points and Weights, N = 20
// DATA ( W(I,3), X(I,3), I = 1, 10 ) /
// * 0.1761400713915212D-01,-0.9931285991850949D+00,
// * 0.4060142980038694D-01,-0.9639719272779138D+00,
// * 0.6267204833410906D-01,-0.9122344282513259D+00,
// * 0.8327674157670475D-01,-0.8391169718222188D+00,
// * 0.1019301198172404D+00,-0.7463319064601508D+00,
// * 0.1181945319615184D+00,-0.6360536807265150D+00,
// * 0.1316886384491766D+00,-0.5108670019508271D+00,
// * 0.1420961093183821D+00,-0.3737060887154196D+00,
// * 0.1491729864726037D+00,-0.2277858511416451D+00,
// * 0.1527533871307259D+00,-0.7652652113349733D-01/
const W: [[f64; 10]; 3] = [
[
0.1713244923791705,
0.3607615730481384,
0.4679139345726904,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
],
[
0.04717533638651177,
0.1069393259953183,
0.1600783285433464,
0.2031674267230659,
0.2334925365383547,
0.2491470458134029,
0.0,
0.0,
0.0,
0.0,
],
[
0.01761400713915212,
0.04060142980038694,
0.06267204833410905,
0.08327674157670475,
0.1019301198172404,
0.1181945319615184,
0.1316886384491766,
0.1420961093183821,
0.1491729864726037,
0.1527533871307259,
],
]; // python script (ignore the leading //): [[float(i[0]) for i in i]+[0.0]*(10-len(i)) for i in [[i.strip().replace('D','e').split(',') for i in i.split('*')[1:] for i in i.strip().split('\n')] for i in "\n".join([a for a in a.split('\n') if 'D+' in a]).split('/')[:3]]]
const X: [[f64; 10]; 3] = [
[
-0.9324695142031522,
-0.6612093864662647,
-0.238619186083197,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
],
[
-0.9815606342467191,
-0.904117256370475,
-0.769902674194305,
-0.5873179542866171,
-0.3678314989981802,
-0.1252334085114692,
0.0,
0.0,
0.0,
0.0,
],
[
-0.9931285991850949,
-0.9639719272779138,
-0.912234428251326,
-0.8391169718222188,
-0.7463319064601508,
-0.636053680726515,
-0.5108670019508271,
-0.3737060887154196,
-0.2277858511416451,
-0.07652652113349732,
],
]; // python script (ignore the leading //): [[float(i[1]) for i in i]+[0.0]*(10-len(i)) for i in [[i.strip().replace('D','e').split(',') for i in i.split('*')[1:] for i in i.strip().split('\n')] for i in "\n".join([a for a in a.split('\n') if 'D+' in a]).split('/')[:3]]]
// IF ( ABS(R) .LT. 0.3 ) THEN
// NG = 1
// LG = 3
// ELSE IF ( ABS(R) .LT. 0.75 ) THEN
// NG = 2
// LG = 6
// ELSE
// NG = 3
// LG = 10
// ENDIF
if r.abs() < 0.3 {
ng = 0;
lg = 3;
} else if r.abs() < 0.75 {
ng = 1;
lg = 6;
} else {
ng = 2;
lg = 10;
}
// H = SH
// K = SK
let h = sh;
let mut k = sk;
// HK = H*K
let mut hk = h * k;
// BVN = 0
// IF ( ABS(R) .LT. 0.925 ) THEN
if r.abs() < 0.925 {
// HS = ( H*H + K*K )/2
let hs = (h * h + k * k) / 2.0;
// ASR = ASIN(R)
let asr = r.asin();
// DO I = 1, LG
// for i in 0..lg{
// // SN = SIN(ASR*( X(I,NG)+1 )/2)
// sn=(asr*(( X[ng][i]+1f64 )/2f64)).sin();
// // BVN = BVN + W(I,NG)*EXP( ( SN*HK - HS )/( 1 - SN*SN ) )
// bvn+=W[ng][i]*((sn*hk-hs)/(1-sn*sn)).exp()
// // SN = SIN(ASR*(-X(I,NG)+1 )/2)
// // BVN = BVN + W(I,NG)*EXP( ( SN*HK - HS )/( 1 - SN*SN ) )
// // END DO
// }
// BVN = BVN*ASR/(2*TWOPI) + MVPHI(-H)*MVPHI(-K)
(0..lg)
.map(|i| {
let sn1 = (asr * ((X[ng][i] + 1.0) / 2.0)).sin();
let sn2 = (asr * ((-X[ng][i] + 1.0) / 2.0)).sin();
W[ng][i]
* (((sn1 * hk - hs) / (1.0 - sn1 * sn1)).exp()
+ ((sn2 * hk - hs) / (1.0 - sn2 * sn2)).exp())
})
.sum::<f64>()
* asr
/ (TWOPI * 2.0)
+ mvphi(-h) * mvphi(-k)
} else {
// ELSE
// IF ( R .LT. 0 ) THEN
// K = -K
// HK = -HK
// ENDIF
if r < 0.0 {
k = -k;
hk = -hk;
}
// IF ( ABS(R) .LT. 1 ) THEN
let bvn = if r.abs() < 1.0 {
// AS = ( 1 - R )*( 1 + R )
let r#as = (1.0 - r) * (1.0 + r);
// A = SQRT(AS)
let a = r#as.sqrt();
// BS = ( H - K )**2
let bs = (h - k) * (h - k);
// C = ( 4 - HK )/8
// D = ( 12 - HK )/16
let c = (4.0 - hk) / 8.0;
let d = (12.0 - hk) / 16.0;
// BVN = A*EXP( -(BS/AS + HK)/2 )
// + *( 1 - C*(BS - AS)*(1 - D*BS/5)/3 + C*D*AS*AS/5 )
let mut bvn = a
* (-(bs / r#as + hk) / 2.0).exp()
* (1.0 - c * (bs - r#as) * (1.0 - d * bs / 5.0) / 3.0 + c * d * r#as * r#as / 5.0);
// IF ( HK .GT. -160 ) THEN
if hk > -160.0 {
// B = SQRT(BS)
let b = bs.sqrt();
// BVN = BVN - EXP(-HK/2)*SQRT(TWOPI)*MVPHI(-B/A)*B
// + *( 1 - C*BS*( 1 - D*BS/5 )/3 )
bvn -= (-hk / 2.0).exp()
* TWOPI.sqrt()
* mvphi(-b / a)
* b
* (1.0 - c * bs * (1.0 - d * bs / 5.0) / 3.0);
// ENDIF
}
// A = A/2
let a = a / 2.0;
// DO I = 1, LG
// XS = ( A*(X(I,NG)+1) )**2
// RS = SQRT( 1 - XS )
// BVN = BVN + A*W(I,NG)*
// + ( EXP( -BS/(2*XS) - HK/(1+RS) )/RS
// + - EXP( -(BS/XS+HK)/2 )*( 1 + C*XS*( 1 + D*XS ) ) )
// XS = AS*(-X(I,NG)+1)**2/4
// RS = SQRT( 1 - XS )
// BVN = BVN + A*W(I,NG)*EXP( -(BS/XS + HK)/2 )
// + *( EXP( -HK*(1-RS)/(2*(1+RS)) )/RS
// + - ( 1 + C*XS*( 1 + D*XS ) ) )
// END DO
-(bvn
+ (0..lg)
.map(|i| {
let xs = (a * (X[ng][i as usize] + 1.0)) * (a * (X[ng][i as usize] + 1.0));
let rs = (1.0 - xs).sqrt();
let bvn = a
* W[ng][i as usize]
* ((-bs / (2.0 * xs) - hk / (1.0 + rs)).exp() / rs
- (-(bs / xs + hk) / 2.0).exp() * (1.0 + c * xs * (1.0 + d * xs)));
let xs =
r#as * (-X[ng][i as usize] + 1.0) * (-X[ng][i as usize] + 1.0) / 4.0;
let rs = (1.0 - xs).sqrt();
bvn + a
* W[ng][i as usize]
* (-(bs / xs + hk) / 2.0).exp()
* ((-hk * (1.0 - rs) / (2.0 * (1.0 + rs))).exp() / rs
- (1.0 + c * xs * (1.0 + d * xs)))
})
.sum::<f64>())
/ TWOPI
// BVN = -BVN/TWOPI
// ENDIF
} else {
0.0
};
// IF ( R .GT. 0 ) BVN = BVN + MVPHI( -MAX( H, K ) )
// IF ( R .LT. 0 ) BVN = -BVN + MAX( ZERO, MVPHI(-H) - MVPHI(-K) )
if r > 0.0 {
bvn + mvphi(-(h.max(k)))
} else {
-bvn + 0f64.max(mvphi(-h) - mvphi(-k))
}
// ENDIF
}
// MVBVU = BVN
// END
}
/// DOUBLE PRECISION FUNCTION MVPHI(Z)
/// *
/// * Normal distribution probabilities accurate to 1d-15.
/// * Reference: J.L. Schonfelder, Math Comp 32(1978), pp 1232-1240.
/// *
fn mvphi(z: f64) -> f64 {
// INTEGER I, IM
// DOUBLE PRECISION A(0:43), BM, B, BP, P, RTWO, T, XA, Z
// PARAMETER( RTWO = 1.414213562373095048801688724209D0, IM = 24 )
const IM: i32 = 24;
const RTWO: f64 = 1.414213562373095048801688724209;
// SAVE A
// DATA ( A(I), I = 0, 43 )/
// & 6.10143081923200417926465815756D-1,
// & -4.34841272712577471828182820888D-1,
// & 1.76351193643605501125840298123D-1,
// & -6.0710795609249414860051215825D-2,
// & 1.7712068995694114486147141191D-2,
// & -4.321119385567293818599864968D-3,
// & 8.54216676887098678819832055D-4,
// & -1.27155090609162742628893940D-4,
// & 1.1248167243671189468847072D-5, 3.13063885421820972630152D-7,
// & -2.70988068537762022009086D-7, 3.0737622701407688440959D-8,
// & 2.515620384817622937314D-9, -1.028929921320319127590D-9,
// & 2.9944052119949939363D-11, 2.6051789687266936290D-11,
// & -2.634839924171969386D-12, -6.43404509890636443D-13,
// & 1.12457401801663447D-13, 1.7281533389986098D-14,
// & -4.264101694942375D-15, -5.45371977880191D-16,
// & 1.58697607761671D-16, 2.0899837844334D-17,
// & -5.900526869409D-18, -9.41893387554D-19, 2.14977356470D-19,
// & 4.6660985008D-20, -7.243011862D-21, -2.387966824D-21,
// & 1.91177535D-22, 1.20482568D-22, -6.72377D-25, -5.747997D-24,
// & -4.28493D-25, 2.44856D-25, 4.3793D-26, -8.151D-27, -3.089D-27,
// & 9.3D-29, 1.74D-28, 1.6D-29, -8.0D-30, -2.0D-30 /
// *
const A: [f64; 44] = [
6.10143081923200417926465815756e-1,
-4.34841272712577471828182820888e-1,
1.76351193643605501125840298123e-1,
-6.0710795609249414860051215825e-2,
1.7712068995694114486147141191e-2,
-4.321119385567293818599864968e-3,
8.54216676887098678819832055e-4,
-1.27155090609162742628893940e-4,
1.1248167243671189468847072e-5,
3.13063885421820972630152e-7,
-2.70988068537762022009086e-7,
3.0737622701407688440959e-8,
2.515620384817622937314e-9,
-1.028929921320319127590e-9,
2.9944052119949939363e-11,
2.6051789687266936290e-11,
-2.634839924171969386e-12,
-6.43404509890636443e-13,
1.12457401801663447e-13,
1.7281533389986098e-14,
-4.264101694942375e-15,
-5.45371977880191e-16,
1.58697607761671e-16,
2.0899837844334e-17,
-5.900526869409e-18,
-9.41893387554e-19,
2.14977356470e-19,
4.6660985008e-20,
-7.243011862e-21,
-2.387966824e-21,
1.91177535e-22,
1.20482568e-22,
-6.72377e-25,
-5.747997e-24,
-4.28493e-25,
2.44856e-25,
4.3793e-26,
-8.151e-27,
-3.089e-27,
9.3e-29,
1.74e-28,
1.6e-29,
-8.0e-30,
-2.0e-30,
];
// XA = ABS(Z)/RTWO
let xa = z.abs() / RTWO;
// IF ( XA .GT. 100 ) THEN
let p = if xa >= 100.0 {
0.0
// P = 0
// ELSE
} else {
// T = ( 8*XA - 30 ) / ( 4*XA + 15 )
let t = (8.0 * xa - 30.0) / (4.0 * xa + 15.0);
let mut bm = 0.0;
let mut b = 0.0;
let mut bp = 0.0;
// BM = 0
// B = 0
// DO I = IM, 0, -1
// BP = B
// B = BM
// BM = T*B - BP + A(I)
// END DO
for i in (0..=IM).rev() {
bp = b;
b = bm;
bm = t * b - bp + A[i as usize]
}
// P = EXP( -XA*XA )*( BM - BP )/4
(-xa * xa).exp() * (bm - bp) / 4.0
// END IF
};
// IF ( Z .GT. 0 ) P = 1 - P
// MVPHI = P
if z > 0.0 {
1.0 - p
} else {
p
}
// END
}
src/static.rs
static W0: [f64; 3] =
[
0.1713244923791705,
0.3607615730481384,
0.4679139345726904,
];
static W1:[f64;6]=
[
0.04717533638651177,
0.1069393259953183,
0.1600783285433464,
0.2031674267230659,
0.2334925365383547,
0.2491470458134029,
];
static W2:[f64;10]=
[
0.01761400713915212,
0.04060142980038694,
0.06267204833410905,
0.08327674157670475,
0.1019301198172404,
0.1181945319615184,
0.1316886384491766,
0.1420961093183821,
0.1491729864726037,
0.1527533871307259,
];
static X0: [f64; 3] =
[
-0.9324695142031522,
-0.6612093864662647,
-0.238619186083197,
];
static X1:[f64; 6] = [
-0.9815606342467191,
-0.904117256370475,
-0.769902674194305,
-0.5873179542866171,
-0.3678314989981802,
-0.1252334085114692,
];
static X2:[f64;10]=[
-0.9931285991850949,
-0.9639719272779138,
-0.912234428251326,
-0.8391169718222188,
-0.7463319064601508,
-0.636053680726515,
-0.5108670019508271,
-0.3737060887154196,
-0.2277858511416451,
-0.07652652113349732,
];
static A: [f64; 44] = [
6.10143081923200417926465815756e-1,
-4.34841272712577471828182820888e-1,
1.76351193643605501125840298123e-1,
-6.0710795609249414860051215825e-2,
1.7712068995694114486147141191e-2,
-4.321119385567293818599864968e-3,
8.54216676887098678819832055e-4,
-1.27155090609162742628893940e-4,
1.1248167243671189468847072e-5,
3.13063885421820972630152e-7,
-2.70988068537762022009086e-7,
3.0737622701407688440959e-8,
2.515620384817622937314e-9,
-1.028929921320319127590e-9,
2.9944052119949939363e-11,
2.6051789687266936290e-11,
-2.634839924171969386e-12,
-6.43404509890636443e-13,
1.12457401801663447e-13,
1.7281533389986098e-14,
-4.264101694942375e-15,
-5.45371977880191e-16,
1.58697607761671e-16,
2.0899837844334e-17,
-5.900526869409e-18,
-9.41893387554e-19,
2.14977356470e-19,
4.6660985008e-20,
-7.243011862e-21,
-2.387966824e-21,
1.91177535e-22,
1.20482568e-22,
-6.72377e-25,
-5.747997e-24,
-4.28493e-25,
2.44856e-25,
4.3793e-26,
-8.151e-27,
-3.089e-27,
9.3e-29,
1.74e-28,
1.6e-29,
-8.0e-30,
-2.0e-30,
];
pub fn mvbvn(mut li: f64, mut lj: f64, mut ui: f64, mut uj: f64, mut corr: f64) -> f64 {
if li >= ui || lj >= uj {
0.0
} else {
if li.abs() > ui.abs() {
(li, ui, corr) = (-ui, -li, -corr)
}
if lj.abs() > uj.abs() {
(lj, uj, corr) = (-uj, -lj, -corr)
}
// if li==f64::NEG_INFINITY {MVPHI(uj)-MVPHI(lj)}
mvbvu(li, lj, corr)
- if uj != f64::INFINITY {
mvbvu(li, uj, corr)
} else {
0.0
}
- if ui != f64::INFINITY {
mvbvu(ui, lj, corr)
} else {
0.0
}
+ if ui + uj != f64::INFINITY {
mvbvu(ui, uj, corr)
} else {
0.0
}
}
}
fn mvbvu(sh: f64, sk: f64, r: f64) -> f64 {
// DOUBLE PRECISION BVN, SH, SK, R, ZERO, TWOPI
// let mut bvn=0f64;
// INTEGER I, LG, NG
// PARAMETER ( ZERO = 0, TWOPI = 6.283185307179586D0 )
const TWOPI: f64 = 6.283185307179586;
// DOUBLE PRECISION X(10,3), W(10,3), AS, A, B, C, D, RS, XS
// DOUBLE PRECISION MVPHI, SN, ASR, H, K, BS, HS, HK
// SAVE X, W
// * Gauss Legendre Points and Weights, N = 6
// DATA ( W(I,1), X(I,1), I = 1, 3 ) /
// * 0.1713244923791705D+00,-0.9324695142031522D+00,
// * 0.3607615730481384D+00,-0.6612093864662647D+00,
// * 0.4679139345726904D+00,-0.2386191860831970D+00/
// * Gauss Legendre Points and Weights, N = 12
// DATA ( W(I,2), X(I,2), I = 1, 6 ) /
// * 0.4717533638651177D-01,-0.9815606342467191D+00,
// * 0.1069393259953183D+00,-0.9041172563704750D+00,
// * 0.1600783285433464D+00,-0.7699026741943050D+00,
// * 0.2031674267230659D+00,-0.5873179542866171D+00,
// * 0.2334925365383547D+00,-0.3678314989981802D+00,
// * 0.2491470458134029D+00,-0.1252334085114692D+00/
// * Gauss Legendre Points and Weights, N = 20
// DATA ( W(I,3), X(I,3), I = 1, 10 ) /
// * 0.1761400713915212D-01,-0.9931285991850949D+00,
// * 0.4060142980038694D-01,-0.9639719272779138D+00,
// * 0.6267204833410906D-01,-0.9122344282513259D+00,
// * 0.8327674157670475D-01,-0.8391169718222188D+00,
// * 0.1019301198172404D+00,-0.7463319064601508D+00,
// * 0.1181945319615184D+00,-0.6360536807265150D+00,
// * 0.1316886384491766D+00,-0.5108670019508271D+00,
// * 0.1420961093183821D+00,-0.3737060887154196D+00,
// * 0.1491729864726037D+00,-0.2277858511416451D+00,
// * 0.1527533871307259D+00,-0.7652652113349733D-01/
// IF ( ABS(R) .LT. 0.3 ) THEN
// NG = 1
// LG = 3
// ELSE IF ( ABS(R) .LT. 0.75 ) THEN
// NG = 2
// LG = 6
// ELSE
// NG = 3
// LG = 10
// ENDIF
// H = SH
// K = SK
let h = sh;
let mut k = sk;
// HK = H*K
let mut hk = h * k;
// BVN = 0
// IF ( ABS(R) .LT. 0.925 ) THEN
if r.abs() < 0.925 {
// HS = ( H*H + K*K )/2
let hs = (h * h + k * k) / 2.0;
// ASR = ASIN(R)
let asr = r.asin();
// DO I = 1, LG
// for i in 0..lg{
// // SN = SIN(ASR*( X(I,NG)+1 )/2)
// sn=(asr*(( X[ng][i]+1f64 )/2f64)).sin();
// // BVN = BVN + W(I,NG)*EXP( ( SN*HK - HS )/( 1 - SN*SN ) )
// bvn+=W[ng][i]*((sn*hk-hs)/(1-sn*sn)).exp()
// // SN = SIN(ASR*(-X(I,NG)+1 )/2)
// // BVN = BVN + W(I,NG)*EXP( ( SN*HK - HS )/( 1 - SN*SN ) )
// // END DO
// }
// BVN = BVN*ASR/(2*TWOPI) + MVPHI(-H)*MVPHI(-K)
(if r.abs() < 0.3 {
X0.iter().zip(W0.iter())
} else if r.abs() < 0.75 {
X1.iter().zip(W1.iter())
} else {
X2.iter().zip(W2.iter())
}).map(|(x,w)| {
let sn1 = (asr * ((x + 1.0) / 2.0)).sin();
let sn2 = (asr * ((-x + 1.0) / 2.0)).sin();
w
* (((sn1 * hk - hs) / (1.0 - sn1 * sn1)).exp()
+ ((sn2 * hk - hs) / (1.0 - sn2 * sn2)).exp())
})
.sum::<f64>()
* asr
/ (TWOPI * 2.0)
+ mvphi(-h) * mvphi(-k)
} else {
// ELSE
// IF ( R .LT. 0 ) THEN
// K = -K
// HK = -HK
// ENDIF
if r < 0.0 {
k = -k;
hk = -hk;
}
// IF ( ABS(R) .LT. 1 ) THEN
let bvn = if r.abs() < 1.0 {
// AS = ( 1 - R )*( 1 + R )
let r#as = (1.0 - r) * (1.0 + r);
// A = SQRT(AS)
let a = r#as.sqrt();
// BS = ( H - K )**2
let bs = (h - k) * (h - k);
// C = ( 4 - HK )/8
// D = ( 12 - HK )/16
let c = (4.0 - hk) / 8.0;
let d = (12.0 - hk) / 16.0;
// BVN = A*EXP( -(BS/AS + HK)/2 )
// + *( 1 - C*(BS - AS)*(1 - D*BS/5)/3 + C*D*AS*AS/5 )
let mut bvn = a
* (-(bs / r#as + hk) / 2.0).exp()
* (1.0 - c * (bs - r#as) * (1.0 - d * bs / 5.0) / 3.0 + c * d * r#as * r#as / 5.0);
// IF ( HK .GT. -160 ) THEN
if hk > -160.0 {
// B = SQRT(BS)
let b = bs.sqrt();
// BVN = BVN - EXP(-HK/2)*SQRT(TWOPI)*MVPHI(-B/A)*B
// + *( 1 - C*BS*( 1 - D*BS/5 )/3 )
bvn -= (-hk / 2.0).exp()
* TWOPI.sqrt()
* mvphi(-b / a)
* b
* (1.0 - c * bs * (1.0 - d * bs / 5.0) / 3.0);
// ENDIF
}
// A = A/2
let a = a / 2.0;
// DO I = 1, LG
// XS = ( A*(X(I,NG)+1) )**2
// RS = SQRT( 1 - XS )
// BVN = BVN + A*W(I,NG)*
// + ( EXP( -BS/(2*XS) - HK/(1+RS) )/RS
// + - EXP( -(BS/XS+HK)/2 )*( 1 + C*XS*( 1 + D*XS ) ) )
// XS = AS*(-X(I,NG)+1)**2/4
// RS = SQRT( 1 - XS )
// BVN = BVN + A*W(I,NG)*EXP( -(BS/XS + HK)/2 )
// + *( EXP( -HK*(1-RS)/(2*(1+RS)) )/RS
// + - ( 1 + C*XS*( 1 + D*XS ) ) )
// END DO
-(bvn
+ (if r.abs() < 0.3 {
X0.iter().zip(W0.iter())
} else if r.abs() < 0.75 {
X1.iter().zip(W1.iter())
} else {
X2.iter().zip(W2.iter())
}).map(|(x,w)| {
let xs = (a * (x + 1.0)) * (a * (x + 1.0));
let rs = (1.0 - xs).sqrt();
let bvn = a
* w
* ((-bs / (2.0 * xs) - hk / (1.0 + rs)).exp() / rs
- (-(bs / xs + hk) / 2.0).exp() * (1.0 + c * xs * (1.0 + d * xs)));
let xs =
r#as * (-x + 1.0) * (-x + 1.0) / 4.0;
let rs = (1.0 - xs).sqrt();
bvn + a
* w
* (-(bs / xs + hk) / 2.0).exp()
* ((-hk * (1.0 - rs) / (2.0 * (1.0 + rs))).exp() / rs
- (1.0 + c * xs * (1.0 + d * xs)))
})
.sum::<f64>())
/ TWOPI
// BVN = -BVN/TWOPI
// ENDIF
} else {
0.0
};
// IF ( R .GT. 0 ) BVN = BVN + MVPHI( -MAX( H, K ) )
// IF ( R .LT. 0 ) BVN = -BVN + MAX( ZERO, MVPHI(-H) - MVPHI(-K) )
if r > 0.0 {
bvn + mvphi(-(h.max(k)))
} else {
-bvn + 0f64.max(mvphi(-h) - mvphi(-k))
}
// ENDIF
}
// MVBVU = BVN
// END
}
fn mvphi(z: f64) -> f64 {
// INTEGER I, IM
// DOUBLE PRECISION A(0:43), BM, B, BP, P, RTWO, T, XA, Z
// PARAMETER( RTWO = 1.414213562373095048801688724209D0, IM = 24 )
const IM: i32 = 24;
const RTWO: f64 = 1.414213562373095048801688724209;
// SAVE A
// DATA ( A(I), I = 0, 43 )/
// & 6.10143081923200417926465815756D-1,
// & -4.34841272712577471828182820888D-1,
// & 1.76351193643605501125840298123D-1,
// & -6.0710795609249414860051215825D-2,
// & 1.7712068995694114486147141191D-2,
// & -4.321119385567293818599864968D-3,
// & 8.54216676887098678819832055D-4,
// & -1.27155090609162742628893940D-4,
// & 1.1248167243671189468847072D-5, 3.13063885421820972630152D-7,
// & -2.70988068537762022009086D-7, 3.0737622701407688440959D-8,
// & 2.515620384817622937314D-9, -1.028929921320319127590D-9,
// & 2.9944052119949939363D-11, 2.6051789687266936290D-11,
// & -2.634839924171969386D-12, -6.43404509890636443D-13,
// & 1.12457401801663447D-13, 1.7281533389986098D-14,
// & -4.264101694942375D-15, -5.45371977880191D-16,
// & 1.58697607761671D-16, 2.0899837844334D-17,
// & -5.900526869409D-18, -9.41893387554D-19, 2.14977356470D-19,
// & 4.6660985008D-20, -7.243011862D-21, -2.387966824D-21,
// & 1.91177535D-22, 1.20482568D-22, -6.72377D-25, -5.747997D-24,
// & -4.28493D-25, 2.44856D-25, 4.3793D-26, -8.151D-27, -3.089D-27,
// & 9.3D-29, 1.74D-28, 1.6D-29, -8.0D-30, -2.0D-30 /
// *
// XA = ABS(Z)/RTWO
let xa = z.abs() / RTWO;
// IF ( XA .GT. 100 ) THEN
let p = if xa >= 100.0 {
0.0
// P = 0
// ELSE
} else {
// T = ( 8*XA - 30 ) / ( 4*XA + 15 )
let t = (8.0 * xa - 30.0) / (4.0 * xa + 15.0);
let mut bm = 0.0;
let mut b = 0.0;
let mut bp = 0.0;
// BM = 0
// B = 0
// DO I = IM, 0, -1
// BP = B
// B = BM
// BM = T*B - BP + A(I)
// END DO
for i in (0..=IM).rev() {
bp = b;
b = bm;
bm = t * b - bp + A[i as usize]
}
// P = EXP( -XA*XA )*( BM - BP )/4
(-xa * xa).exp() * (bm - bp) / 4.0
// END IF
};
// IF ( Z .GT. 0 ) P = 1 - P
// MVPHI = P
if z > 0.0 {
1.0 - p
} else {
p
}
// END
}
src/param.rs
pub static SW0: [f64; 3] =
[
0.1713244923791705,
0.3607615730481384,
0.4679139345726904,
];
pub static SW1:[f64;6]=
[
0.04717533638651177,
0.1069393259953183,
0.1600783285433464,
0.2031674267230659,
0.2334925365383547,
0.2491470458134029,
];
pub static SW2:[f64;10]=
[
0.01761400713915212,
0.04060142980038694,
0.06267204833410905,
0.08327674157670475,
0.1019301198172404,
0.1181945319615184,
0.1316886384491766,
0.1420961093183821,
0.1491729864726037,
0.1527533871307259,
];
pub static SX0: [f64; 3] =
[
-0.9324695142031522,
-0.6612093864662647,
-0.238619186083197,
];
pub static SX1:[f64; 6] = [
-0.9815606342467191,
-0.904117256370475,
-0.769902674194305,
-0.5873179542866171,
-0.3678314989981802,
-0.1252334085114692,
];
pub static SX2:[f64;10]=[
-0.9931285991850949,
-0.9639719272779138,
-0.912234428251326,
-0.8391169718222188,
-0.7463319064601508,
-0.636053680726515,
-0.5108670019508271,
-0.3737060887154196,
-0.2277858511416451,
-0.07652652113349732,
];
pub static SA: [f64; 44] = [
6.10143081923200417926465815756e-1,
-4.34841272712577471828182820888e-1,
1.76351193643605501125840298123e-1,
-6.0710795609249414860051215825e-2,
1.7712068995694114486147141191e-2,
-4.321119385567293818599864968e-3,
8.54216676887098678819832055e-4,
-1.27155090609162742628893940e-4,
1.1248167243671189468847072e-5,
3.13063885421820972630152e-7,
-2.70988068537762022009086e-7,
3.0737622701407688440959e-8,
2.515620384817622937314e-9,
-1.028929921320319127590e-9,
2.9944052119949939363e-11,
2.6051789687266936290e-11,
-2.634839924171969386e-12,
-6.43404509890636443e-13,
1.12457401801663447e-13,
1.7281533389986098e-14,
-4.264101694942375e-15,
-5.45371977880191e-16,
1.58697607761671e-16,
2.0899837844334e-17,
-5.900526869409e-18,
-9.41893387554e-19,
2.14977356470e-19,
4.6660985008e-20,
-7.243011862e-21,
-2.387966824e-21,
1.91177535e-22,
1.20482568e-22,
-6.72377e-25,
-5.747997e-24,
-4.28493e-25,
2.44856e-25,
4.3793e-26,
-8.151e-27,
-3.089e-27,
9.3e-29,
1.74e-28,
1.6e-29,
-8.0e-30,
-2.0e-30,
];
pub fn mvbvn(mut li: f64, mut lj: f64, mut ui: f64, mut uj: f64, mut corr: f64, W0:&[f64;3],W1:&[f64;6],W2:&[f64;10],X0:&[f64;3],X1:&[f64;6],X2:&[f64;10],A:&[f64;44]) -> f64 {
if li >= ui || lj >= uj {
0.0
} else {
if li.abs() > ui.abs() {
(li, ui, corr) = (-ui, -li, -corr)
}
if lj.abs() > uj.abs() {
(lj, uj, corr) = (-uj, -lj, -corr)
}
// if li==f64::NEG_INFINITY {MVPHI(uj)-MVPHI(lj)}
mvbvu(li, lj, corr,W0,W1,W2,X0,X1,X2,A)
- if uj != f64::INFINITY {
mvbvu(li, uj, corr,W0,W1,W2,X0,X1,X2,A)
} else {
0.0
}
- if ui != f64::INFINITY {
mvbvu(ui, lj, corr,W0,W1,W2,X0,X1,X2,A)
} else {
0.0
}
+ if ui + uj != f64::INFINITY {
mvbvu(ui, uj, corr,W0,W1,W2,X0,X1,X2,A)
} else {
0.0
}
}
}
fn mvbvu(sh: f64, sk: f64, r: f64, W0:&[f64;3],W1:&[f64;6],W2:&[f64;10],X0:&[f64;3],X1:&[f64;6],X2:&[f64;10],A:&[f64;44]) -> f64 {
// DOUBLE PRECISION BVN, SH, SK, R, ZERO, TWOPI
// let mut bvn=0f64;
// INTEGER I, LG, NG
// PARAMETER ( ZERO = 0, TWOPI = 6.283185307179586D0 )
const TWOPI: f64 = 6.283185307179586;
// DOUBLE PRECISION X(10,3), W(10,3), AS, A, B, C, D, RS, XS
// DOUBLE PRECISION MVPHI, SN, ASR, H, K, BS, HS, HK
// SAVE X, W
// * Gauss Legendre Points and Weights, N = 6
// DATA ( W(I,1), X(I,1), I = 1, 3 ) /
// * 0.1713244923791705D+00,-0.9324695142031522D+00,
// * 0.3607615730481384D+00,-0.6612093864662647D+00,
// * 0.4679139345726904D+00,-0.2386191860831970D+00/
// * Gauss Legendre Points and Weights, N = 12
// DATA ( W(I,2), X(I,2), I = 1, 6 ) /
// * 0.4717533638651177D-01,-0.9815606342467191D+00,
// * 0.1069393259953183D+00,-0.9041172563704750D+00,
// * 0.1600783285433464D+00,-0.7699026741943050D+00,
// * 0.2031674267230659D+00,-0.5873179542866171D+00,
// * 0.2334925365383547D+00,-0.3678314989981802D+00,
// * 0.2491470458134029D+00,-0.1252334085114692D+00/
// * Gauss Legendre Points and Weights, N = 20
// DATA ( W(I,3), X(I,3), I = 1, 10 ) /
// * 0.1761400713915212D-01,-0.9931285991850949D+00,
// * 0.4060142980038694D-01,-0.9639719272779138D+00,
// * 0.6267204833410906D-01,-0.9122344282513259D+00,
// * 0.8327674157670475D-01,-0.8391169718222188D+00,
// * 0.1019301198172404D+00,-0.7463319064601508D+00,
// * 0.1181945319615184D+00,-0.6360536807265150D+00,
// * 0.1316886384491766D+00,-0.5108670019508271D+00,
// * 0.1420961093183821D+00,-0.3737060887154196D+00,
// * 0.1491729864726037D+00,-0.2277858511416451D+00,
// * 0.1527533871307259D+00,-0.7652652113349733D-01/
// IF ( ABS(R) .LT. 0.3 ) THEN
// NG = 1
// LG = 3
// ELSE IF ( ABS(R) .LT. 0.75 ) THEN
// NG = 2
// LG = 6
// ELSE
// NG = 3
// LG = 10
// ENDIF
// H = SH
// K = SK
let h = sh;
let mut k = sk;
// HK = H*K
let mut hk = h * k;
// BVN = 0
// IF ( ABS(R) .LT. 0.925 ) THEN
if r.abs() < 0.925 {
// HS = ( H*H + K*K )/2
let hs = (h * h + k * k) / 2.0;
// ASR = ASIN(R)
let asr = r.asin();
// DO I = 1, LG
// for i in 0..lg{
// // SN = SIN(ASR*( X(I,NG)+1 )/2)
// sn=(asr*(( X[ng][i]+1f64 )/2f64)).sin();
// // BVN = BVN + W(I,NG)*EXP( ( SN*HK - HS )/( 1 - SN*SN ) )
// bvn+=W[ng][i]*((sn*hk-hs)/(1-sn*sn)).exp()
// // SN = SIN(ASR*(-X(I,NG)+1 )/2)
// // BVN = BVN + W(I,NG)*EXP( ( SN*HK - HS )/( 1 - SN*SN ) )
// // END DO
// }
// BVN = BVN*ASR/(2*TWOPI) + MVPHI(-H)*MVPHI(-K)
(if r.abs() < 0.3 {
X0.iter().zip(W0.iter())
} else if r.abs() < 0.75 {
X1.iter().zip(W1.iter())
} else {
X2.iter().zip(W2.iter())
}).map(|(x,w)| {
let sn1 = (asr * ((x + 1.0) / 2.0)).sin();
let sn2 = (asr * ((-x + 1.0) / 2.0)).sin();
w
* (((sn1 * hk - hs) / (1.0 - sn1 * sn1)).exp()
+ ((sn2 * hk - hs) / (1.0 - sn2 * sn2)).exp())
})
.sum::<f64>()
* asr
/ (TWOPI * 2.0)
+ mvphi(-h,A) * mvphi(-k,A)
} else {
// ELSE
// IF ( R .LT. 0 ) THEN
// K = -K
// HK = -HK
// ENDIF
if r < 0.0 {
k = -k;
hk = -hk;
}
// IF ( ABS(R) .LT. 1 ) THEN
let bvn = if r.abs() < 1.0 {
// AS = ( 1 - R )*( 1 + R )
let r#as = (1.0 - r) * (1.0 + r);
// A = SQRT(AS)
let a = r#as.sqrt();
// BS = ( H - K )**2
let bs = (h - k) * (h - k);
// C = ( 4 - HK )/8
// D = ( 12 - HK )/16
let c = (4.0 - hk) / 8.0;
let d = (12.0 - hk) / 16.0;
// BVN = A*EXP( -(BS/AS + HK)/2 )
// + *( 1 - C*(BS - AS)*(1 - D*BS/5)/3 + C*D*AS*AS/5 )
let mut bvn = a
* (-(bs / r#as + hk) / 2.0).exp()
* (1.0 - c * (bs - r#as) * (1.0 - d * bs / 5.0) / 3.0 + c * d * r#as * r#as / 5.0);
// IF ( HK .GT. -160 ) THEN
if hk > -160.0 {
// B = SQRT(BS)
let b = bs.sqrt();
// BVN = BVN - EXP(-HK/2)*SQRT(TWOPI)*MVPHI(-B/A)*B
// + *( 1 - C*BS*( 1 - D*BS/5 )/3 )
bvn -= (-hk / 2.0).exp()
* TWOPI.sqrt()
* mvphi(-b / a,A)
* b
* (1.0 - c * bs * (1.0 - d * bs / 5.0) / 3.0);
// ENDIF
}
// A = A/2
let a = a / 2.0;
// DO I = 1, LG
// XS = ( A*(X(I,NG)+1) )**2
// RS = SQRT( 1 - XS )
// BVN = BVN + A*W(I,NG)*
// + ( EXP( -BS/(2*XS) - HK/(1+RS) )/RS
// + - EXP( -(BS/XS+HK)/2 )*( 1 + C*XS*( 1 + D*XS ) ) )
// XS = AS*(-X(I,NG)+1)**2/4
// RS = SQRT( 1 - XS )
// BVN = BVN + A*W(I,NG)*EXP( -(BS/XS + HK)/2 )
// + *( EXP( -HK*(1-RS)/(2*(1+RS)) )/RS
// + - ( 1 + C*XS*( 1 + D*XS ) ) )
// END DO
-(bvn
+ (if r.abs() < 0.3 {
X0.iter().zip(W0.iter())
} else if r.abs() < 0.75 {
X1.iter().zip(W1.iter())
} else {
X2.iter().zip(W2.iter())
}).map(|(x,w)| {
let xs = (a * (x + 1.0)) * (a * (x + 1.0));
let rs = (1.0 - xs).sqrt();
let bvn = a
* w
* ((-bs / (2.0 * xs) - hk / (1.0 + rs)).exp() / rs
- (-(bs / xs + hk) / 2.0).exp() * (1.0 + c * xs * (1.0 + d * xs)));
let xs =
r#as * (-x + 1.0) * (-x + 1.0) / 4.0;
let rs = (1.0 - xs).sqrt();
bvn + a
* w
* (-(bs / xs + hk) / 2.0).exp()
* ((-hk * (1.0 - rs) / (2.0 * (1.0 + rs))).exp() / rs
- (1.0 + c * xs * (1.0 + d * xs)))
})
.sum::<f64>())
/ TWOPI
// BVN = -BVN/TWOPI
// ENDIF
} else {
0.0
};
// IF ( R .GT. 0 ) BVN = BVN + MVPHI( -MAX( H, K ) )
// IF ( R .LT. 0 ) BVN = -BVN + MAX( ZERO, MVPHI(-H) - MVPHI(-K) )
if r > 0.0 {
bvn + mvphi(-(h.max(k)),A)
} else {
-bvn + 0f64.max(mvphi(-h,A) - mvphi(-k,A))
}
// ENDIF
}
// MVBVU = BVN
// END
}
fn mvphi(z: f64, A:&[f64;44]) -> f64 {
// INTEGER I, IM
// DOUBLE PRECISION A(0:43), BM, B, BP, P, RTWO, T, XA, Z
// PARAMETER( RTWO = 1.414213562373095048801688724209D0, IM = 24 )
const IM: i32 = 24;
const RTWO: f64 = 1.414213562373095048801688724209;
// SAVE A
// DATA ( A(I), I = 0, 43 )/
// & 6.10143081923200417926465815756D-1,
// & -4.34841272712577471828182820888D-1,
// & 1.76351193643605501125840298123D-1,
// & -6.0710795609249414860051215825D-2,
// & 1.7712068995694114486147141191D-2,
// & -4.321119385567293818599864968D-3,
// & 8.54216676887098678819832055D-4,
// & -1.27155090609162742628893940D-4,
// & 1.1248167243671189468847072D-5, 3.13063885421820972630152D-7,
// & -2.70988068537762022009086D-7, 3.0737622701407688440959D-8,
// & 2.515620384817622937314D-9, -1.028929921320319127590D-9,
// & 2.9944052119949939363D-11, 2.6051789687266936290D-11,
// & -2.634839924171969386D-12, -6.43404509890636443D-13,
// & 1.12457401801663447D-13, 1.7281533389986098D-14,
// & -4.264101694942375D-15, -5.45371977880191D-16,
// & 1.58697607761671D-16, 2.0899837844334D-17,
// & -5.900526869409D-18, -9.41893387554D-19, 2.14977356470D-19,
// & 4.6660985008D-20, -7.243011862D-21, -2.387966824D-21,
// & 1.91177535D-22, 1.20482568D-22, -6.72377D-25, -5.747997D-24,
// & -4.28493D-25, 2.44856D-25, 4.3793D-26, -8.151D-27, -3.089D-27,
// & 9.3D-29, 1.74D-28, 1.6D-29, -8.0D-30, -2.0D-30 /
// *
// XA = ABS(Z)/RTWO
let xa = z.abs() / RTWO;
// IF ( XA .GT. 100 ) THEN
let p = if xa >= 100.0 {
0.0
// P = 0
// ELSE
} else {
// T = ( 8*XA - 30 ) / ( 4*XA + 15 )
let t = (8.0 * xa - 30.0) / (4.0 * xa + 15.0);
let mut bm = 0.0;
let mut b = 0.0;
let mut bp = 0.0;
// BM = 0
// B = 0
// DO I = IM, 0, -1
// BP = B
// B = BM
// BM = T*B - BP + A(I)
// END DO
for i in (0..=IM).rev() {
bp = b;
b = bm;
bm = t * b - bp + A[i as usize]
}
// P = EXP( -XA*XA )*( BM - BP )/4
(-xa * xa).exp() * (bm - bp) / 4.0
// END IF
};
// IF ( Z .GT. 0 ) P = 1 - P
// MVPHI = P
if z > 0.0 {
1.0 - p
} else {
p
}
// END
}
benchmark
use criterion::{black_box, criterion_group, criterion_main, Criterion};
pub fn bench_orig(c: &mut Criterion) {
use benchmark_static::orig::*;
c.bench_function("orig", |b| b.iter(|| black_box([[-1f64,-1.,1.,1.];100].into_iter().zip((0..100).map(|x|(x*2-99) as f64/100.))).map(|x|mvbvn(x.0[0],x.0[1],x.0[2],x.0[3],x.1)).sum::<f64>()));
}
pub fn bench_global(c: &mut Criterion) {
use benchmark_static::r#static::*;
c.bench_function("global", |b| b.iter(|| black_box([[-1f64,-1.,1.,1.];100].into_iter().zip((0..100).map(|x|(x*2-99) as f64/100.))).map(|x|mvbvn(x.0[0],x.0[1],x.0[2],x.0[3],x.1)).sum::<f64>()));
}
pub fn bench_param(c: &mut Criterion) {
use benchmark_static::param::*;
let (W0,W1,W2,X0,X1,X2,A)=(&SW0,&SW1,&SW2,&SX0,&SX1,&SX2,&SA);
c.bench_function("param", |b| b.iter(|| black_box([[-1f64,-1.,1.,1.];100].into_iter().zip((0..100).map(|x|(x*2-99) as f64/100.))).map(|x|mvbvn(x.0[0],x.0[1],x.0[2],x.0[3],x.1,W0,W1,W2,X0,X1,X2,A)).sum::<f64>()));
}
criterion_group!(orig, bench_orig);
criterion_group!(global, bench_global);
criterion_group!(param, bench_param);
criterion_main!(orig, global, param);
differences between static.rs
and param.rs
:
$ diff static.rs param.rs
1c1
< static W0: [f64; 3] =
---
> pub static SW0: [f64; 3] =
7c7
< static W1:[f64;6]=
---
> pub static SW1:[f64;6]=
16c16
< static W2:[f64;10]=
---
> pub static SW2:[f64;10]=
29c29
< static X0: [f64; 3] =
---
> pub static SX0: [f64; 3] =
35c35
< static X1:[f64; 6] = [
---
> pub static SX1:[f64; 6] = [
43c43
< static X2:[f64;10]=[
---
> pub static SX2:[f64;10]=[
56c56
< static A: [f64; 44] = [
---
> pub static SA: [f64; 44] = [
103c103
< pub fn mvbvn(mut li: f64, mut lj: f64, mut ui: f64, mut uj: f64, mut corr: f64) -> f64 {
---
> pub fn mvbvn(mut li: f64, mut lj: f64, mut ui: f64, mut uj: f64, mut corr: f64, W0:&[f64;3],W1:&[f64;6],W2:&[f64;10],X0:&[f64;3],X1:&[f64;6],X2:&[f64;10],A:&[f64;44]) -> f64 {
114c114
< mvbvu(li, lj, corr)
---
> mvbvu(li, lj, corr,W0,W1,W2,X0,X1,X2,A)
116c116
< mvbvu(li, uj, corr)
---
> mvbvu(li, uj, corr,W0,W1,W2,X0,X1,X2,A)
121c121
< mvbvu(ui, lj, corr)
---
> mvbvu(ui, lj, corr,W0,W1,W2,X0,X1,X2,A)
126c126
< mvbvu(ui, uj, corr)
---
> mvbvu(ui, uj, corr,W0,W1,W2,X0,X1,X2,A)
133c133
< fn mvbvu(sh: f64, sk: f64, r: f64) -> f64 {
---
> fn mvbvu(sh: f64, sk: f64, r: f64, W0:&[f64;3],W1:&[f64;6],W2:&[f64;10],X0:&[f64;3],X1:&[f64;6],X2:&[f64;10],A:&[f64;44]) -> f64 {
218c218
< + mvphi(-h) * mvphi(-k)
---
> + mvphi(-h,A) * mvphi(-k,A)
254c254
< * mvphi(-b / a)
---
> * mvphi(-b / a,A)
307c307
< bvn + mvphi(-(h.max(k)))
---
> bvn + mvphi(-(h.max(k)),A)
309c309
< -bvn + 0f64.max(mvphi(-h) - mvphi(-k))
---
> -bvn + 0f64.max(mvphi(-h,A) - mvphi(-k,A))
318c318
< fn mvphi(z: f64) -> f64 {
---
> fn mvphi(z: f64, A:&[f64;44]) -> f64 {
Results:
Finished bench [optimized] target(s) in 0.04s
Running unittests src/lib.rs (/me/ben/target/release/deps/benchmark_static-56b725c82118e0da)
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Running benches/bench.rs (/me/ben/target/release/deps/bench-7b5d4883affc7873)
orig time: [187.64 µs 187.71 µs 187.83 µs]
change: [-0.3591% -0.2672% -0.1605%] (p = 0.00 < 0.05)
Change within noise threshold.
Found 13 outliers among 100 measurements (13.00%)
2 (2.00%) high mild
11 (11.00%) high severe
global time: [188.64 µs 188.78 µs 189.09 µs]
change: [+0.0078% +0.1025% +0.2603%] (p = 0.14 > 0.05)
No change in performance detected.
Found 10 outliers among 100 measurements (10.00%)
1 (1.00%) low severe
1 (1.00%) low mild
3 (3.00%) high mild
5 (5.00%) high severe
param time: [190.78 µs 190.80 µs 190.81 µs]
change: [-0.6868% -0.6719% -0.6578%] (p = 0.00 < 0.05)
Change within noise threshold.
Found 6 outliers among 100 measurements (6.00%)
1 (1.00%) low mild
4 (4.00%) high mild
1 (1.00%) high severe