fastnum 0.7.5

Fast decimal numbers library
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
macro_rules! test_impl {
    (D, $bits: literal) => {
        paste::paste! { test_impl!(SIGNED: $bits, [< dec $bits >], [<D $bits>]); }
    };
    (UD, $bits: literal) => {
        paste::paste! { test_impl!(UNSIGNED: $bits, [< udec $bits >], [<UD $bits>]); }
    };
    (UNSIGNED: $bits: tt, $dec: ident, $D: ident) => {
        mod $dec {
            use rstest::*;
            use std::cmp::{max, min};
            use fastnum::{$dec, $D};

            super::test_impl!(COMMON:: $bits, $dec, $D, THIS);
            super::test_impl!(UNSIGNED:: $bits, $dec, $D, THIS);
        }
    };
    (SIGNED: $bits: tt, $dec: ident, $D: ident) => {
        mod $dec {
            use rstest::*;
            use std::cmp::{max, min};
            use fastnum::{$dec, $D};

            super::test_impl!(COMMON:: $bits, $dec, $D, THIS);
            super::test_impl!(SIGNED:: $bits, $dec, $D, THIS);
        }
    };
    (COMMON:: 512, $dec: ident, $D: ident, THIS) => {
        super::test_impl!(COMMON:: 256, $dec, $D);

        #[rstest(::trace)]
        #[case($dec!(1.414213562373095048801688724209698078569671875376948073176679730000000000000000000000000000000000000), $dec!(1.41421356237309504880168872420969807856967187537694807317667974000000000))]
        #[case($dec!(1.414213562373095048801688724209698078569671875376948073176679730000000000000000000000000000000000000), $dec!(11.41421356237309504880168872420969807856967187537694807317667974000000000))]
        fn test_cmp_512(#[case] a: $D, #[case] b: $D) {
            #[allow(clippy::eq_op)]
            (assert_eq!(a, a));

            #[allow(clippy::eq_op)]
            (assert_eq!(b, b));

            assert_ne!(a, b);
            assert!(a < b);
            assert!(a <= b);
            assert!(b > a);
            assert!(b >= a);
            assert_eq!(max(a, b), b);
            assert_eq!(min(a, b), a)
        }
    };
    (UNSIGNED:: 512, $dec: ident, $D: ident, THIS) => {
        super::test_impl!(UNSIGNED:: 256, $dec, $D);
    };
    (SIGNED:: 512, $dec: ident, $D: ident, THIS) => {
        super::test_impl!(SIGNED:: 256, $dec, $D);

        #[rstest(::trace)]
        #[case($dec!(-1.414213562373095048801688724209698078569671875376948073176679730000000000000000000000000000000000000), $dec!(-11.41421356237309504880168872420969807856967187537694807317667974000000000e-2))]
        #[case($dec!(-11.41421356237309504880168872420969807856967187537694807317667974000000000), $dec!(-1.414213562373095048801688724209698078569671875376948073176679730000000000000000000000000000000000000))]
        fn test_cmp_signed_512(#[case] a: $D, #[case] b: $D) {
            #[allow(clippy::eq_op)]
            (assert_eq!(a, a));

            #[allow(clippy::eq_op)]
            (assert_eq!(b, b));

            assert_ne!(a, b);
            assert!(a < b);
            assert!(a <= b);
            assert!(b > a);
            assert!(b >= a);
            assert_eq!(max(a, b), b);
            assert_eq!(min(a, b), a)
        }
    };

    (COMMON:: 256, $dec: ident, $D: ident, THIS) => {
        super::test_impl!(COMMON:: 256, $dec, $D);
    };
    (COMMON:: 256, $dec: ident, $D: ident) => {
        super::test_impl!(COMMON:: 128, $dec, $D);

        #[rstest(::trace)]
        #[case($dec!(472697816888807260.1604), $dec!(472697816888807260.16040000000000000000001))]
        #[case($dec!(1), $dec!(1.0000000000000000000000000000000000000000000000000001))]
        #[case($dec!(1000000000000000000000000000000000000000), $dec!(1e41))]
        #[case($dec!(1116386634271380982470843247639640260491505327092723527088459), $dec!(759522625769651746138617259189939751893902453291243506584717e2))]
        fn test_cmp_256(#[case] a: $D, #[case] b: $D) {
            #[allow(clippy::eq_op)]
            (assert_eq!(a, a));

            #[allow(clippy::eq_op)]
            (assert_eq!(b, b));

            assert_ne!(a, b);
            assert!(a < b);
            assert!(a <= b);
            assert!(b > a);
            assert!(b >= a);
            assert_eq!(max(a, b), b);
            assert_eq!(min(a, b), a)
        }
    };
    (UNSIGNED:: 256, $dec: ident, $D: ident, THIS) => {
        super::test_impl!(UNSIGNED:: 256, $dec, $D);
    };
    (UNSIGNED:: 256, $dec: ident, $D: ident) => {
        super::test_impl!(UNSIGNED:: 128, $dec, $D);
    };
    (SIGNED:: 256, $dec: ident, $D: ident, THIS) => {
        super::test_impl!(SIGNED:: 256, $dec, $D);
    };
    (SIGNED:: 256, $dec: ident, $D: ident) => {
        super::test_impl!(SIGNED:: 128, $dec, $D);

        #[rstest(::trace)]
        #[case($dec!(-1.0000000000000000000000000000000000000000000000000001), $dec!(-1))]
        fn test_cmp_signed_256(#[case] a: $D, #[case] b: $D) {
            #[allow(clippy::eq_op)]
            (assert_eq!(a, a));

            #[allow(clippy::eq_op)]
            (assert_eq!(b, b));

            assert_ne!(a, b);
            assert!(a < b);
            assert!(a <= b);
            assert!(b > a);
            assert!(b >= a);
            assert_eq!(max(a, b), b);
            assert_eq!(min(a, b), a)
        }
    };

    (COMMON:: 128, $dec: ident, $D: ident, THIS) => {
        super::test_impl!(COMMON:: 128, $dec, $D);
    };
    (COMMON:: 128, $dec: ident, $D: ident) => {
        #[rstest(::trace)]
        #[case($dec!(0), $dec!(1))]
        #[case($dec!(1), $dec!(2))]
        #[case($dec!(1), $dec!(10))]
        #[case($dec!(2), $dec!(3))]
        #[case($dec!(100), $dec!(100.1))]
        #[case($dec!(1e2), $dec!(100.1))]
        #[case($dec!(100), $dec!(1.1e2))]
        #[case($dec!(1.2345), $dec!(1.2346))]
        #[case($dec!(25.6), $dec!(25.8))]
        #[case($dec!(1e-9223), $dec!(1))]
        #[case($dec!(1e-9223), $dec!(1e9223))]
        #[case($dec!(1), $dec!(340282366920938463463374607431768211455))]
        #[case($dec!(500), $dec!(51e1))]
        #[case($dec!(44e1), $dec!(500))]
        #[case($dec!(1234000000000), $dec!(12345e9))]
        #[case($dec!(1514932018891593916341142774e-24), $dec!(1514932018891593916341142773.0001))]
        #[case($dec!(1e-32767), $dec!(1e32767))]
        #[case($dec!(2), $dec!(0.2e2))]
        #[case($dec!(1e-900), $dec!(1e45))]
        #[case($dec!(1e-900), $dec!(1e+900))]
        #[case($dec!(35_000), $dec!(192051.716384861040546579908080116424889))]
        #[case($dec!(35e-80), $dec!(19205.1716384861040546579908080116424889))]
        #[case($dec!(19205.1716384861040546579908080116424889), $dec!(35_000))]
        #[case($dec!(192051.716384861040546579908080116424889), $dec!(35e80))]
        #[case($dec!(35e-80), $dec!(192051.716384861040546579908080116424889))]
        fn test_cmp(#[case] a: $D, #[case] b: $D) {
            #[allow(clippy::eq_op)]
            (assert_eq!(a, a));

            #[allow(clippy::eq_op)]
            (assert_eq!(b, b));

            assert_ne!(a, b);
            assert!(a < b);
            assert!(a <= b);
            assert!(b > a);
            assert!(b >= a);
            assert_eq!(max(a, b), b);
            assert_eq!(min(a, b), a)
        }

        #[rstest(::trace)]
        #[case($dec!(0), $dec!(0))]
        #[case($dec!(00), $dec!(0))]
        #[case($dec!(0), $dec!(0.00))]
        #[case($dec!(1), $dec!(1))]
        #[case($dec!(00001), $dec!(1))]
        #[case($dec!(00001), $dec!(1.0000))]
        #[case($dec!(1), $dec!(1.00))]
        #[case($dec!(10), $dec!(10))]
        #[case($dec!(10), $dec!(1e1))]
        #[case($dec!(1.1), $dec!(1.1))]
        #[case($dec!(1.2e-2), $dec!(0.012))]
        #[case($dec!(5000), $dec!(50e2))]
        #[case($dec!(0.000034500), $dec!(345e-7))]
        #[case($dec!(1514932018891593.916341142773), $dec!(1514932018891593916341142773e-12))]
        #[case($dec!(1e32768), $dec!(1e32768))]
        #[case($dec!(1e-32767), $dec!(1e-32767))]
        #[case($dec!(2), $dec!(0.2e1))]
        #[case($dec!(0e1), $dec!(0.0))]
        #[case($dec!(0e1), $dec!(0.0))]
        #[case($dec!(0e0), $dec!(0.0))]
        #[case($dec!(0e-0), $dec!(0.0))]
        #[case($dec!(0901300e-3), $dec!(901.3))]
        #[case($dec!(0.901300e+3), $dec!(901.3))]
        #[case($dec!(0e-1), $dec!(0.0))]
        #[case($dec!(2123121e1231), $dec!(212.3121e1235))]
        fn test_eq(#[case] a: $D, #[case] b: $D) {
            #[allow(clippy::eq_op)]
            (assert_eq!(a, a));

            #[allow(clippy::eq_op)]
            (assert_eq!(b, b));

            assert_eq!(a, b);

            assert!(!(a < b));
            assert!(!(b > a));

            assert!(a <= b);
            assert!(a >= b);

            assert_eq!(b, a);
            assert!(a <= b);
            assert!(a >= b);
        }

        #[rstest(::trace)]
        #[case($D::INFINITY, $D::INFINITY)]
        fn test_eq_special(#[case] a: $D, #[case] b: $D) {
             assert_eq!(a, b);
        }

        #[rstest(::trace)]
        #[case($D::NAN, $D::NAN)]
        #[case($D::ONE, $D::NAN)]
        #[case($D::NAN, $D::ONE)]
        #[case($D::INFINITY, $D::NAN)]
        fn test_ne_special(#[case] a: $D, #[case] b: $D) {
            assert_ne!(a, b);
        }

        #[rstest(::trace)]
        #[case($D::ZERO, $D::ONE)]
        #[case($D::ONE, $D::MAX)]
        #[case($D::MAX, $D::INFINITY)]
        #[case($D::INFINITY, $D::NAN)]
        fn test_cmp_special(#[case] a: $D, #[case] b: $D) {
            assert!(a < b);
        }

        #[rstest(::trace)]
        fn test_sort() {
            let mut positions = vec![
                $dec!(2.0),
                $dec!(4.0),
                $dec!(1.0),
                $dec!(5.0),
                $dec!(3.0),
                $dec!(3.0),
                $D::INFINITY,
                $D::ZERO,
            ];

            positions.sort_by(|a, b| a.cmp(&b));
            itertools::assert_equal(positions, vec![
                $D::ZERO,
                $dec!(1.0),
                $dec!(2.0),
                $dec!(3.0),
                $dec!(3.0),
                $dec!(4.0),
                $dec!(5.0),
                $D::INFINITY,
            ]);
        }
    };
    (UNSIGNED:: 128, $dec: ident, $D: ident, THIS) => {
        super::test_impl!(UNSIGNED:: 128, $dec, $D);
    };
    (UNSIGNED:: 128, $dec: ident, $D: ident) => {

    };
    (SIGNED:: 128, $dec: ident, $D: ident, THIS) => {
        super::test_impl!(SIGNED:: 128, $dec, $D);
    };
    (SIGNED:: 128, $dec: ident, $D: ident) => {
        #[rstest(::trace)]
        fn test_zero_signed() {
            assert_eq!($dec!(-0), $dec!(0));
            assert_eq!($dec!(-0), $dec!(+0));
            assert_eq!($dec!(0), $dec!(-0));

            assert!($dec!(-0) <= $dec!(0));
            assert!($dec!(-0) < $dec!(0));

            assert!($dec!(0) >= $dec!(-0));
            assert!($dec!(0) > $dec!(-0));

            assert_eq!(max($dec!(0), $dec!(-0)), $dec!(0));
            assert_eq!(min($dec!(0), $dec!(-0)), $dec!(-0))
        }

        #[rstest(::trace)]
        #[case($dec!(-1), $dec!(1))]
        #[case($dec!(-1), $dec!(0))]
        #[case($dec!(-1), $dec!(-0))]
        #[case($dec!(-1), $dec!(+0))]
        #[case($dec!(-10), $dec!(10))]
        #[case($dec!(-1), $dec!(10))]
        #[case($dec!(-1.1), $dec!(1.01))]
        #[case($dec!(-0.001), $dec!(-0.000000001))]
        #[case($dec!(-0.001), $dec!(+0.000000001))]
        fn test_cmp_signed(#[case] a: $D, #[case] b: $D) {
            #[allow(clippy::eq_op)]
            (assert_eq!(a, a));

            #[allow(clippy::eq_op)]
            (assert_eq!(b, b));

            assert_ne!(a, b);
            assert!(a <= b);
            assert!(a < b);
            assert!(b > a);
            assert!(b >= a);
            assert_eq!(max(a, b), b);
            assert_eq!(min(a, b), a)
        }

        #[rstest(::trace)]
        #[case($dec!(0), $dec!(0))]
        #[case($dec!(0), $dec!(+0))]
        #[case($dec!(-0), $dec!(-0))]
        #[case($dec!(+0), $dec!(+0))]
        #[case($dec!(+0), $dec!(-0))]
        #[case($dec!(-0), $dec!(+0))]
        #[case($dec!(0), $dec!(-0))]
        #[case($dec!(+1.1), $dec!(+1.1))]
        #[case($dec!(-1.1), $dec!(-1.1))]
        #[case($dec!(-1), $dec!(-1000e-3))]
        #[case($dec!(-0.000034500), $dec!(-345e-7))]
        fn test_eq_signed(#[case] a: $D, #[case] b: $D) {
            #[allow(clippy::eq_op)]
            (assert_eq!(a, a));

            #[allow(clippy::eq_op)]
            (assert_eq!(b, b));

            assert_eq!(a, b);
            assert_eq!(b, a);
        }

        #[rstest(::trace)]
        #[case($D::NEG_INFINITY, $D::NEG_INFINITY)]
        fn test_eq_special_signed(#[case] a: $D, #[case] b: $D) {
             assert_eq!(a, b);
        }

        #[rstest(::trace)]
        #[case($D::NEG_INFINITY, $D::NAN)]
        fn test_ne_special_signed(#[case] a: $D, #[case] b: $D) {
            assert_ne!(a, b);
        }

        #[rstest(::trace)]
        #[case($D::NEG_INFINITY, $D::MIN)]
        #[case($D::MIN, $D::ONE.neg())]
        #[case($D::ONE.neg(), $D::ZERO.neg())]
        #[case($D::ZERO.neg(), $D::ZERO)]
        fn test_cmp_special_signed(#[case] a: $D, #[case] b: $D) {
            assert!(a < b);
        }

        #[rstest(::trace)]
        fn test_sort_signed() {
            let mut positions = vec![
                $dec!(2.0),
                $dec!(4.0),
                $dec!(1.0),
                $dec!(5.0),
                $dec!(3.0),
                $dec!(3.0),
                $D::NEG_INFINITY,
                $D::INFINITY,
                $D::ZERO,
                $dec!(-1.0),
                $dec!(-5.0),
                $dec!(-4.0),
                $dec!(-2.0),
                $dec!(-3.0),
                $D::ZERO.neg(),
            ];

            positions.sort_by(|a, b| a.cmp(&b));
            itertools::assert_equal(positions, vec![
                $D::NEG_INFINITY,
                $dec!(-5.0),
                $dec!(-4.0),
                $dec!(-3.0),
                $dec!(-2.0),
                $dec!(-1.0),
                $D::ZERO.neg(),
                $D::ZERO,
                $dec!(1.0),
                $dec!(2.0),
                $dec!(3.0),
                $dec!(3.0),
                $dec!(4.0),
                $dec!(5.0),
                $D::INFINITY,
            ]);
        }
    };
}

pub(crate) use test_impl;