@@ -6,36 +6,18 @@ extern crate num_integer;
66extern crate num_traits;
77extern crate test;
88
9+ use std:: cmp:: { min, max} ;
10+ use std:: fmt:: Debug ;
911use num_integer:: Integer ;
1012use num_traits:: { AsPrimitive , PrimInt , WrappingAdd , WrappingMul } ;
1113use test:: { black_box, Bencher } ;
1214
15+ // --- Utilities for RNG ----------------------------------------------------
16+
1317trait BenchInteger : Integer + PrimInt + WrappingAdd + WrappingMul + ' static { }
1418
1519impl < T > BenchInteger for T where T : Integer + PrimInt + WrappingAdd + WrappingMul + ' static { }
1620
17- trait NaiveAverage {
18- fn naive_average_floor ( & self , other : & Self ) -> Self ;
19- fn naive_average_ceil ( & self , other : & Self ) -> Self ;
20- }
21-
22- trait UncheckedAverage {
23- fn unchecked_average_floor ( & self , other : & Self ) -> Self ;
24- fn unchecked_average_ceil ( & self , other : & Self ) -> Self ;
25- }
26-
27- fn bench < T , F > ( b : & mut Bencher , v : & [ ( T , T ) ] , f : F )
28- where
29- T : Integer ,
30- F : Fn ( & T , & T ) -> T ,
31- {
32- b. iter ( || {
33- for ( x, y) in v {
34- black_box ( f ( x, y) ) ;
35- }
36- } ) ;
37- }
38-
3921// Simple PRNG so we don't have to worry about rand compatibility
4022fn lcg < T > ( x : T ) -> T
4123where
@@ -49,26 +31,43 @@ where
4931 x. wrapping_mul ( & LCG_A . as_ ( ) ) . wrapping_add ( & LCG_C . as_ ( ) )
5032}
5133
34+ // --- Alt. Implementations -------------------------------------------------
35+
36+ trait NaiveAverage {
37+ fn naive_average_ceil ( & self , other : & Self ) -> Self ;
38+ fn naive_average_floor ( & self , other : & Self ) -> Self ;
39+ }
40+
41+ trait UncheckedAverage {
42+ fn unchecked_average_ceil ( & self , other : & Self ) -> Self ;
43+ fn unchecked_average_floor ( & self , other : & Self ) -> Self ;
44+ }
45+
46+ trait ModuloAverage {
47+ fn modulo_average_ceil ( & self , other : & Self ) -> Self ;
48+ fn modulo_average_floor ( & self , other : & Self ) -> Self ;
49+ }
50+
5251macro_rules! naive_average {
5352 ( $T: ident) => {
5453 impl super :: NaiveAverage for $T {
5554 fn naive_average_floor( & self , other: & $T) -> $T {
5655 match self . checked_add( * other) {
57- Some ( z) => z / 2 ,
56+ Some ( z) => z. div_floor ( & 2 ) ,
5857 None => {
5958 if self > other {
6059 let diff = self - other;
61- other + diff / 2
60+ other + diff. div_floor ( & 2 )
6261 } else {
6362 let diff = other - self ;
64- self + diff / 2
63+ self + diff. div_floor ( & 2 )
6564 }
6665 }
6766 }
6867 }
6968 fn naive_average_ceil( & self , other: & $T) -> $T {
7069 match self . checked_add( * other) . and_then( |x| x. checked_add( 1 ) ) {
71- Some ( z) => z / 2 ,
70+ Some ( z) => z. div_ceil ( & 2 ) ,
7271 None => {
7372 if self > other {
7473 let diff = self - other;
@@ -97,16 +96,95 @@ macro_rules! unchecked_average {
9796 } ;
9897}
9998
99+ macro_rules! modulo_average {
100+ ( $T: ident) => {
101+ impl super :: ModuloAverage for $T {
102+ fn modulo_average_ceil( & self , other: & $T) -> $T {
103+ let ( q1, r1) = self . div_mod_floor( & 2 ) ;
104+ let ( q2, r2) = other. div_mod_floor( & 2 ) ;
105+ q1 + q2 + ( r1 * r2)
106+ }
107+ fn modulo_average_floor( & self , other: & $T) -> $T {
108+ let ( q1, r1) = self . div_mod_floor( & 2 ) ;
109+ let ( q2, r2) = other. div_mod_floor( & 2 ) ;
110+ q1 + q2 + ( r1 * r2)
111+ }
112+ }
113+ } ;
114+ }
115+
116+ // --- Bench functions ------------------------------------------------------
117+
118+ fn bench_unchecked < T , F > ( b : & mut Bencher , v : & [ ( T , T ) ] , f : F )
119+ where
120+ T : Integer + Debug + Copy ,
121+ F : Fn ( & T , & T ) -> T ,
122+ {
123+ b. iter ( || {
124+ for ( x, y) in v {
125+ black_box ( f ( x, y) ) ;
126+ }
127+ } ) ;
128+ }
129+
130+ fn bench_ceil < T , F > ( b : & mut Bencher , v : & [ ( T , T ) ] , f : F )
131+ where
132+ T : Integer + Debug + Copy ,
133+ F : Fn ( & T , & T ) -> T ,
134+ {
135+ for & ( i, j) in v {
136+ let rt = f ( & i, & j) ;
137+ let ( a, b) = ( min ( i, j) , max ( i, j) ) ;
138+ if ( b - a) . is_even ( ) {
139+ assert_eq ! ( rt - a, b - rt) ;
140+ } else {
141+ assert_eq ! ( rt - a, b - rt + T :: one( ) ) ;
142+ }
143+ }
144+ bench_unchecked ( b, v, f) ;
145+ }
146+
147+ fn bench_floor < T , F > ( b : & mut Bencher , v : & [ ( T , T ) ] , f : F )
148+ where
149+ T : Integer + Debug + Copy ,
150+ F : Fn ( & T , & T ) -> T ,
151+ {
152+ for & ( i, j) in v {
153+ let rt = f ( & i, & j) ;
154+ let ( a, b) = ( min ( i, j) , max ( i, j) ) ;
155+ println ! ( "{:?} + {:?} / 2 = {:?}" , a, b, rt) ;
156+ // if both number are the same sign, check rt is in the middle
157+ if ( a < T :: zero ( ) ) == ( b < T :: zero ( ) ) {
158+ if ( b - a) . is_even ( ) {
159+ assert_eq ! ( rt - a, b - rt) ;
160+ } else {
161+ assert_eq ! ( rt - a + T :: one( ) , b - rt) ;
162+ }
163+ // if both number have a different sign,
164+ } else {
165+ if ( a + b) . is_even ( ) {
166+ assert_eq ! ( rt, ( a + b) / ( T :: one( ) + T :: one( ) ) )
167+ } else {
168+ assert_eq ! ( rt, ( a + b - T :: one( ) ) / ( T :: one( ) + T :: one( ) ) )
169+ }
170+ }
171+ }
172+ bench_unchecked ( b, v, f) ;
173+ }
174+
175+ // --- Bench implementation -------------------------------------------------
176+
100177macro_rules! bench_average {
101178 ( $( $T: ident) ,* ) => { $(
102179 mod $T {
103180 use test:: Bencher ;
104- use num_integer:: Average ;
105- use UncheckedAverage ;
106- use NaiveAverage ;
181+ use num_integer:: { Average , Integer } ;
182+ use super :: { UncheckedAverage , NaiveAverage , ModuloAverage } ;
183+ use super :: { bench_ceil , bench_floor , bench_unchecked } ;
107184
108185 naive_average!( $T) ;
109186 unchecked_average!( $T) ;
187+ modulo_average!( $T) ;
110188
111189 const SIZE : $T = 30 ;
112190
@@ -133,59 +211,99 @@ macro_rules! bench_average {
133211 . collect( )
134212 }
135213
136- #[ bench]
137- fn average_floor_small( b: & mut Bencher ) {
138- let v = small( ) ;
139- super :: bench( b, & v, |x: & $T, y: & $T| x. average_floor( y) ) ;
140- }
214+ mod floor {
141215
142- #[ bench]
143- fn average_floor_small_naive( b: & mut Bencher ) {
144- let v = small( ) ;
145- super :: bench( b, & v, |x: & $T, y: & $T| x. naive_average_floor( y) ) ;
146- }
216+ use super :: * ;
147217
148- #[ bench]
149- fn average_floor_small_unchecked( b: & mut Bencher ) {
150- let v = small( ) ;
151- super :: bench( b, & v, |x: & $T, y: & $T| x. unchecked_average_floor( y) ) ;
152- }
218+ mod small {
153219
154- #[ bench]
155- fn average_floor_overflowing( b: & mut Bencher ) {
156- let v = overflowing( ) ;
157- super :: bench( b, & v, |x: & $T, y: & $T| x. average_floor( y) ) ;
158- }
220+ use super :: * ;
159221
160- #[ bench]
161- fn average_floor_overflowing_naive ( b: & mut Bencher ) {
162- let v = overflowing ( ) ;
163- super :: bench ( b, & v, |x: & $T, y: & $T| x. naive_average_floor ( y) ) ;
164- }
222+ #[ bench]
223+ fn optimized ( b: & mut Bencher ) {
224+ let v = small ( ) ;
225+ bench_floor ( b, & v, |x: & $T, y: & $T| x. average_floor ( y) ) ;
226+ }
165227
166- #[ bench]
167- fn average_floor_overflowing_unchecked ( b: & mut Bencher ) {
168- let v = overflowing ( ) ;
169- super :: bench ( b, & v, |x: & $T, y: & $T| x. unchecked_average_floor ( y) ) ;
170- }
228+ #[ bench]
229+ fn naive ( b: & mut Bencher ) {
230+ let v = small ( ) ;
231+ bench_floor ( b, & v, |x: & $T, y: & $T| x. naive_average_floor ( y) ) ;
232+ }
171233
172- #[ bench]
173- fn average_floor_rand ( b: & mut Bencher ) {
174- let v = rand ( ) ;
175- super :: bench ( b, & v, |x: & $T, y: & $T| x. average_floor ( y) ) ;
176- }
234+ #[ bench]
235+ fn unchecked ( b: & mut Bencher ) {
236+ let v = small ( ) ;
237+ bench_unchecked ( b, & v, |x: & $T, y: & $T| x. unchecked_average_floor ( y) ) ;
238+ }
177239
178- #[ bench]
179- fn average_floor_rand_naive( b: & mut Bencher ) {
180- let v = rand( ) ;
181- super :: bench( b, & v, |x: & $T, y: & $T| x. naive_average_floor( y) ) ;
182- }
240+ #[ bench]
241+ fn modulo( b: & mut Bencher ) {
242+ let v = small( ) ;
243+ bench_floor( b, & v, |x: & $T, y: & $T| x. modulo_average_floor( y) ) ;
244+ }
245+ }
246+
247+ mod overflowing {
248+
249+ use super :: * ;
250+
251+ #[ bench]
252+ fn optimized( b: & mut Bencher ) {
253+ let v = overflowing( ) ;
254+ bench_floor( b, & v, |x: & $T, y: & $T| x. average_floor( y) ) ;
255+ }
256+
257+ #[ bench]
258+ fn naive( b: & mut Bencher ) {
259+ let v = overflowing( ) ;
260+ bench_floor( b, & v, |x: & $T, y: & $T| x. naive_average_floor( y) ) ;
261+ }
262+
263+ #[ bench]
264+ fn unchecked( b: & mut Bencher ) {
265+ let v = overflowing( ) ;
266+ bench_unchecked( b, & v, |x: & $T, y: & $T| x. unchecked_average_floor( y) ) ;
267+ }
268+
269+ #[ bench]
270+ fn modulo( b: & mut Bencher ) {
271+ let v = overflowing( ) ;
272+ bench_floor( b, & v, |x: & $T, y: & $T| x. modulo_average_floor( y) ) ;
273+ }
274+ }
275+
276+ mod rand {
277+
278+ use super :: * ;
279+
280+ #[ bench]
281+ fn optimized( b: & mut Bencher ) {
282+ let v = rand( ) ;
283+ bench_floor( b, & v, |x: & $T, y: & $T| x. average_floor( y) ) ;
284+ }
285+
286+ #[ bench]
287+ fn naive( b: & mut Bencher ) {
288+ let v = rand( ) ;
289+ bench_floor( b, & v, |x: & $T, y: & $T| x. naive_average_floor( y) ) ;
290+ }
291+
292+ #[ bench]
293+ fn unchecked( b: & mut Bencher ) {
294+ let v = rand( ) ;
295+ bench_unchecked( b, & v, |x: & $T, y: & $T| x. unchecked_average_floor( y) ) ;
296+ }
297+
298+ #[ bench]
299+ fn modulo( b: & mut Bencher ) {
300+ let v = rand( ) ;
301+ bench_floor( b, & v, |x: & $T, y: & $T| x. modulo_average_floor( y) ) ;
302+ }
303+ }
183304
184- #[ bench]
185- fn average_floor_rand_unchecked( b: & mut Bencher ) {
186- let v = rand( ) ;
187- super :: bench( b, & v, |x: & $T, y: & $T| x. unchecked_average_floor( y) ) ;
188305 }
306+
189307 }
190308 ) * }
191309}
0 commit comments