@@ -643,7 +643,7 @@ impl Price {
643
643
644
644
#[ cfg( test) ]
645
645
mod test {
646
- // use quickcheck::TestResult;
646
+ use quickcheck:: TestResult ;
647
647
use std:: convert:: TryFrom ;
648
648
649
649
use crate :: price:: {
@@ -2051,135 +2051,134 @@ mod test {
2051
2051
fails ( i64:: MIN , pc ( 100 , 10 , -9 ) , 0 , pc ( 0 , 12 , -9 ) , 0 , -9 ) ;
2052
2052
}
2053
2053
2054
- // pub fn construct_quickcheck_affine_combination_price(price: i64) -> Price {
2055
- // return Price {
2056
- // price: price,
2057
- // conf: 0,
2058
- // expo: -9,
2059
- // publish_time: 0,
2060
- // };
2061
- // }
2062
-
2063
- // // quickcheck to confirm affine_combination introduces no error if normalization done
2064
- // explicitly // on prices first this quickcheck calls affine_combination with two sets of
2065
- // almost // identical inputs: the first set has potentially unnormalized prices, the second
2066
- // set // simply has the normalized versions of those prices this set of checks should pass
2067
- // because // normalization is automatically performed on the prices before they are
2068
- // multiplied // this set of checks passing indicates that it doesn't matter whether the
2069
- // prices passed in are // normalized
2070
- // #[quickcheck]
2071
- // fn quickcheck_affine_combination_normalize_prices(
2072
- // x1_inp: i32,
2073
- // p1: i32,
2074
- // x2_inp: i32,
2075
- // p2: i32,
2076
- // x_query_inp: i32,
2077
- // ) -> TestResult {
2078
- // // generating xs and prices from i32 to limit the range to reasonable values and guard
2079
- // // against overflow/bespoke constraint setting for quickcheck
2080
- // let y1 = construct_quickcheck_affine_combination_price(i64::try_from(p1).ok().unwrap());
2081
- // let y2 = construct_quickcheck_affine_combination_price(i64::try_from(p2).ok().unwrap());
2082
-
2083
- // let x1 = i64::try_from(x1_inp).ok().unwrap();
2084
- // let x2 = i64::try_from(x2_inp).ok().unwrap();
2085
- // let x_query = i64::try_from(x_query_inp).ok().unwrap();
2086
-
2087
- // // stick with single expo for ease of testing and generation
2088
- // let pre_add_expo = -9;
2089
-
2090
- // // require x2 > x1, as needed for affine_combination
2091
- // if x1 >= x2 {
2092
- // return TestResult::discard();
2093
- // }
2094
-
2095
- // // original result
2096
- // let result_orig = Price::affine_combination(x1, y1, x2, y2, x_query,
2097
- // pre_add_expo).unwrap();
2098
-
2099
- // let y1_norm = y1.normalize().unwrap();
2100
- // let y2_norm = y2.normalize().unwrap();
2101
-
2102
- // // result with normalized price inputs
2103
- // let result_norm =
2104
- // Price::affine_combination(x1, y1_norm, x2, y2_norm, x_query, pre_add_expo).unwrap();
2105
-
2106
- // // results should match exactly
2107
- // TestResult::from_bool(result_norm == result_orig)
2108
- // }
2109
-
2110
- // // quickcheck to confirm affine_combination introduces bounded error if close fraction x/y
2111
- // // passed in first this quickcheck calls affine_combination with two sets of similar inputs:
2112
- // // the first set has xs generated by the quickcheck generation process, leading to
2113
- // potentially // inexact fractions that don't fit within 8 digits of precision the second
2114
- // set "normalizes" // down to 8 digits of precision by setting x1 to 0, x2 to 100_000_000,
2115
- // and xquery // proportionally based on the bounds described in the docstring of
2116
- // affine_combination, we // expect error due to this to be leq 4*10^-7
2117
- // #[quickcheck]
2118
- // fn quickcheck_affine_combination_normalize_fractions(
2119
- // x1_inp: i32,
2120
- // p1: i32,
2121
- // x2_inp: i32,
2122
- // p2: i32,
2123
- // x_query_inp: i32,
2124
- // ) -> TestResult {
2125
- // // generating xs and prices from i32 to limit the range to reasonable values and guard
2126
- // // against overflow/bespoke constraint setting for quickcheck
2127
- // let y1 = construct_quickcheck_affine_combination_price(i64::try_from(p1).ok().unwrap());
2128
- // let y2 = construct_quickcheck_affine_combination_price(i64::try_from(p2).ok().unwrap());
2129
-
2130
- // let x1 = i64::try_from(x1_inp).ok().unwrap();
2131
- // let x2 = i64::try_from(x2_inp).ok().unwrap();
2132
- // let x_query = i64::try_from(x_query_inp).ok().unwrap();
2133
-
2134
- // // stick with single expo for ease of testing and generation
2135
- // let pre_add_expo = -9;
2136
-
2137
- // // require x2 > x1, as needed for affine_combination
2138
- // if x1 >= x2 {
2139
- // return TestResult::discard();
2140
- // }
2141
-
2142
- // // constrain x_query to be within 5 interval lengths of x1 or x2
2143
- // if (x_query > x2 + 5 * (x2 - x1)) || (x_query < x1 - 5 * (x2 - x1)) {
2144
- // return TestResult::discard();
2145
- // }
2146
-
2147
- // // generate new xs based on scaling x_1 --> 0, x_2 --> 10^8
2148
- // let x1_new: i64;
2149
- // let xq_new: i64;
2150
- // let x2_new: i64;
2151
-
2152
- // if x2 == 0 {
2153
- // x1_new = x1;
2154
- // xq_new = x_query;
2155
- // x2_new = x2;
2156
- // } else {
2157
- // let mut frac_q2 = Price::fraction(x_query - x1, x2 - x1).unwrap();
2158
- // frac_q2 = frac_q2.scale_to_exponent(-8).unwrap();
2159
-
2160
- // x1_new = 0;
2161
- // xq_new = frac_q2.price;
2162
- // x2_new = 100_000_000 as i64;
2163
- // }
2164
-
2165
- // // original result
2166
- // let result_orig = Price::affine_combination(x1, y1, x2, y2, x_query, pre_add_expo)
2167
- // .unwrap()
2168
- // .scale_to_exponent(-7)
2169
- // .unwrap();
2170
-
2171
- // // xs "normalized" result
2172
- // let result_norm = Price::affine_combination(x1_new, y1, x2_new, y2, xq_new, pre_add_expo)
2173
- // .unwrap()
2174
- // .scale_to_exponent(-7)
2175
- // .unwrap();
2176
-
2177
- // // compute difference in prices
2178
- // let price_diff = result_norm.add(&result_orig.cmul(-1, 0).unwrap()).unwrap();
2179
-
2180
- // // results should differ by less than 4*10^-7
2181
- // TestResult::from_bool((price_diff.price < 4) && (price_diff.price > -4))
2182
- // }
2054
+ pub fn construct_quickcheck_affine_combination_price ( price : i64 ) -> Price {
2055
+ return Price {
2056
+ price : price,
2057
+ conf : 0 ,
2058
+ expo : -9 ,
2059
+ publish_time : 0 ,
2060
+ } ;
2061
+ }
2062
+
2063
+ // quickcheck to confirm affine_combination introduces no error if normalization done
2064
+ // explicitly on prices first this quickcheck calls affine_combination with two sets of
2065
+ // almost identical inputs: the first set has potentially unnormalized prices, the second
2066
+ // set simply has the normalized versions of those prices this set of checks should pass
2067
+ // because normalization is automatically performed on the prices before they are
2068
+ // multiplied this set of checks passing indicates that it doesn't matter whether the
2069
+ // prices passed in are normalized
2070
+ #[ quickcheck]
2071
+ fn quickcheck_affine_combination_normalize_prices (
2072
+ x1_inp : i32 ,
2073
+ p1 : i32 ,
2074
+ x2_inp : i32 ,
2075
+ p2 : i32 ,
2076
+ x_query_inp : i32 ,
2077
+ ) -> TestResult {
2078
+ // generating xs and prices from i32 to limit the range to reasonable values and guard
2079
+ // against overflow/bespoke constraint setting for quickcheck
2080
+ let y1 = construct_quickcheck_affine_combination_price ( i64:: try_from ( p1) . ok ( ) . unwrap ( ) ) ;
2081
+ let y2 = construct_quickcheck_affine_combination_price ( i64:: try_from ( p2) . ok ( ) . unwrap ( ) ) ;
2082
+
2083
+ let x1 = i64:: try_from ( x1_inp) . ok ( ) . unwrap ( ) ;
2084
+ let x2 = i64:: try_from ( x2_inp) . ok ( ) . unwrap ( ) ;
2085
+ let x_query = i64:: try_from ( x_query_inp) . ok ( ) . unwrap ( ) ;
2086
+
2087
+ // stick with single expo for ease of testing and generation
2088
+ let pre_add_expo = -9 ;
2089
+
2090
+ // require x2 > x1, as needed for affine_combination
2091
+ if x1 >= x2 {
2092
+ return TestResult :: discard ( ) ;
2093
+ }
2094
+
2095
+ // original result
2096
+ let result_orig = Price :: affine_combination ( x1, y1, x2, y2, x_query, pre_add_expo) . unwrap ( ) ;
2097
+
2098
+ let y1_norm = y1. normalize ( ) . unwrap ( ) ;
2099
+ let y2_norm = y2. normalize ( ) . unwrap ( ) ;
2100
+
2101
+ // result with normalized price inputs
2102
+ let result_norm =
2103
+ Price :: affine_combination ( x1, y1_norm, x2, y2_norm, x_query, pre_add_expo) . unwrap ( ) ;
2104
+
2105
+ // results should match exactly
2106
+ TestResult :: from_bool ( result_norm == result_orig)
2107
+ }
2108
+
2109
+ // quickcheck to confirm affine_combination introduces bounded error if close fraction x/y
2110
+ // passed in first this quickcheck calls affine_combination with two sets of similar inputs:
2111
+ // the first set has xs generated by the quickcheck generation process, leading to
2112
+ // potentially inexact fractions that don't fit within 8 digits of precision the second
2113
+ // set "normalizes" down to 8 digits of precision by setting x1 to 0, x2 to 100_000_000,
2114
+ // and xquery proportionally based on the bounds described in the docstring of
2115
+ // affine_combination, we expect error due to this to be leq 4*10^-7
2116
+ #[ quickcheck]
2117
+ fn quickcheck_affine_combination_normalize_fractions (
2118
+ x1_inp : i32 ,
2119
+ p1 : i32 ,
2120
+ x2_inp : i32 ,
2121
+ p2 : i32 ,
2122
+ x_query_inp : i32 ,
2123
+ ) -> TestResult {
2124
+ // generating xs and prices from i32 to limit the range to reasonable values and guard
2125
+ // against overflow/bespoke constraint setting for quickcheck
2126
+ let y1 = construct_quickcheck_affine_combination_price ( i64:: try_from ( p1) . ok ( ) . unwrap ( ) ) ;
2127
+ let y2 = construct_quickcheck_affine_combination_price ( i64:: try_from ( p2) . ok ( ) . unwrap ( ) ) ;
2128
+
2129
+ let x1 = i64:: try_from ( x1_inp) . ok ( ) . unwrap ( ) ;
2130
+ let x2 = i64:: try_from ( x2_inp) . ok ( ) . unwrap ( ) ;
2131
+ let x_query = i64:: try_from ( x_query_inp) . ok ( ) . unwrap ( ) ;
2132
+
2133
+ // stick with single expo for ease of testing and generation
2134
+ let pre_add_expo = -9 ;
2135
+
2136
+ // require x2 > x1, as needed for affine_combination
2137
+ if x1 >= x2 {
2138
+ return TestResult :: discard ( ) ;
2139
+ }
2140
+
2141
+ // constrain x_query to be within 5 interval lengths of x1 or x2
2142
+ if ( x_query > x2 + 5 * ( x2 - x1) ) || ( x_query < x1 - 5 * ( x2 - x1) ) {
2143
+ return TestResult :: discard ( ) ;
2144
+ }
2145
+
2146
+ // generate new xs based on scaling x_1 --> 0, x_2 --> 10^8
2147
+ let x1_new: i64 ;
2148
+ let xq_new: i64 ;
2149
+ let x2_new: i64 ;
2150
+
2151
+ if x2 == 0 {
2152
+ x1_new = x1;
2153
+ xq_new = x_query;
2154
+ x2_new = x2;
2155
+ } else {
2156
+ let mut frac_q2 = Price :: fraction ( x_query - x1, x2 - x1) . unwrap ( ) ;
2157
+ frac_q2 = frac_q2. scale_to_exponent ( -8 ) . unwrap ( ) ;
2158
+
2159
+ x1_new = 0 ;
2160
+ xq_new = frac_q2. price ;
2161
+ x2_new = 100_000_000 as i64 ;
2162
+ }
2163
+
2164
+ // original result
2165
+ let result_orig = Price :: affine_combination ( x1, y1, x2, y2, x_query, pre_add_expo)
2166
+ . unwrap ( )
2167
+ . scale_to_exponent ( -7 )
2168
+ . unwrap ( ) ;
2169
+
2170
+ // xs "normalized" result
2171
+ let result_norm = Price :: affine_combination ( x1_new, y1, x2_new, y2, xq_new, pre_add_expo)
2172
+ . unwrap ( )
2173
+ . scale_to_exponent ( -7 )
2174
+ . unwrap ( ) ;
2175
+
2176
+ // compute difference in prices
2177
+ let price_diff = result_norm. add ( & result_orig. cmul ( -1 , 0 ) . unwrap ( ) ) . unwrap ( ) ;
2178
+
2179
+ // results should differ by less than 4*10^-7
2180
+ TestResult :: from_bool ( ( price_diff. price < 4 ) && ( price_diff. price > -4 ) )
2181
+ }
2183
2182
2184
2183
#[ test]
2185
2184
fn test_fraction ( ) {
0 commit comments