Skip to content

Commit bbe3aef

Browse files
committed
Work on bigint
Try splitting part of 'Int' into 'MinInt' so we don't need to implement everything on u256/i256 Add addsub test Add mul/div/rem tests Add cmp test Remove 32-bit div implementation formatting updates disable div tests for now Bigint updates Big update Fix widen mul wrapping add disable duplicate symbols in builtins Apply temporary unord fix from @beetrees #593 tests add lowerhex display errors by ref tests fix-test Update big tests Fix core calls Disable widen_mul for signed Test adding symbols in build.rs Add a feature to compile intrinsics that are missing on the system for testing update Disable f128 tests on platforms without system support add missing build.rs file pull cas file from master testgs print more div values Add a benchmark Work on fixing bit widths Update benchmark
1 parent f3f4dec commit bbe3aef

23 files changed

+933
-191
lines changed

build.rs

-12
Original file line numberDiff line numberDiff line change
@@ -479,10 +479,6 @@ mod c {
479479
("__floatsitf", "floatsitf.c"),
480480
("__floatunditf", "floatunditf.c"),
481481
("__floatunsitf", "floatunsitf.c"),
482-
("__addtf3", "addtf3.c"),
483-
("__multf3", "multf3.c"),
484-
("__subtf3", "subtf3.c"),
485-
("__divtf3", "divtf3.c"),
486482
("__powitf2", "powitf2.c"),
487483
("__fe_getround", "fp_mode.c"),
488484
("__fe_raise_inexact", "fp_mode.c"),
@@ -500,30 +496,22 @@ mod c {
500496
if target_arch == "mips64" {
501497
sources.extend(&[
502498
("__netf2", "comparetf2.c"),
503-
("__addtf3", "addtf3.c"),
504-
("__multf3", "multf3.c"),
505-
("__subtf3", "subtf3.c"),
506499
("__fixtfsi", "fixtfsi.c"),
507500
("__floatsitf", "floatsitf.c"),
508501
("__fixunstfsi", "fixunstfsi.c"),
509502
("__floatunsitf", "floatunsitf.c"),
510503
("__fe_getround", "fp_mode.c"),
511-
("__divtf3", "divtf3.c"),
512504
]);
513505
}
514506

515507
if target_arch == "loongarch64" {
516508
sources.extend(&[
517509
("__netf2", "comparetf2.c"),
518-
("__addtf3", "addtf3.c"),
519-
("__multf3", "multf3.c"),
520-
("__subtf3", "subtf3.c"),
521510
("__fixtfsi", "fixtfsi.c"),
522511
("__floatsitf", "floatsitf.c"),
523512
("__fixunstfsi", "fixunstfsi.c"),
524513
("__floatunsitf", "floatunsitf.c"),
525514
("__fe_getround", "fp_mode.c"),
526-
("__divtf3", "divtf3.c"),
527515
]);
528516
}
529517

src/float/add.rs

+11-11
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::float::Float;
2-
use crate::int::{CastInto, Int};
2+
use crate::int::{CastInto, Int, MinInt};
33

44
/// Returns `a + b`
55
fn add<F: Float>(a: F, b: F) -> F
@@ -57,17 +57,17 @@ where
5757
}
5858

5959
// zero + anything = anything
60-
if a_abs == Int::ZERO {
60+
if a_abs == MinInt::ZERO {
6161
// but we need to get the sign right for zero + zero
62-
if b_abs == Int::ZERO {
62+
if b_abs == MinInt::ZERO {
6363
return F::from_repr(a.repr() & b.repr());
6464
} else {
6565
return b;
6666
}
6767
}
6868

6969
// anything + zero = anything
70-
if b_abs == Int::ZERO {
70+
if b_abs == MinInt::ZERO {
7171
return a;
7272
}
7373
}
@@ -113,10 +113,10 @@ where
113113
// Shift the significand of b by the difference in exponents, with a sticky
114114
// bottom bit to get rounding correct.
115115
let align = a_exponent.wrapping_sub(b_exponent).cast();
116-
if align != Int::ZERO {
116+
if align != MinInt::ZERO {
117117
if align < bits {
118118
let sticky =
119-
F::Int::from_bool(b_significand << bits.wrapping_sub(align).cast() != Int::ZERO);
119+
F::Int::from_bool(b_significand << bits.wrapping_sub(align).cast() != MinInt::ZERO);
120120
b_significand = (b_significand >> align.cast()) | sticky;
121121
} else {
122122
b_significand = one; // sticky; b is known to be non-zero.
@@ -125,8 +125,8 @@ where
125125
if subtraction {
126126
a_significand = a_significand.wrapping_sub(b_significand);
127127
// If a == -b, return +zero.
128-
if a_significand == Int::ZERO {
129-
return F::from_repr(Int::ZERO);
128+
if a_significand == MinInt::ZERO {
129+
return F::from_repr(MinInt::ZERO);
130130
}
131131

132132
// If partial cancellation occured, we need to left-shift the result
@@ -143,8 +143,8 @@ where
143143

144144
// If the addition carried up, we need to right-shift the result and
145145
// adjust the exponent:
146-
if a_significand & implicit_bit << 4 != Int::ZERO {
147-
let sticky = F::Int::from_bool(a_significand & one != Int::ZERO);
146+
if a_significand & implicit_bit << 4 != MinInt::ZERO {
147+
let sticky = F::Int::from_bool(a_significand & one != MinInt::ZERO);
148148
a_significand = a_significand >> 1 | sticky;
149149
a_exponent += 1;
150150
}
@@ -160,7 +160,7 @@ where
160160
// need to shift the significand.
161161
let shift = (1 - a_exponent).cast();
162162
let sticky =
163-
F::Int::from_bool((a_significand << bits.wrapping_sub(shift).cast()) != Int::ZERO);
163+
F::Int::from_bool((a_significand << bits.wrapping_sub(shift).cast()) != MinInt::ZERO);
164164
a_significand = a_significand >> shift.cast() | sticky;
165165
a_exponent = 0;
166166
}

src/float/cmp.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#![allow(unreachable_code)]
22

33
use crate::float::Float;
4-
use crate::int::Int;
4+
use crate::int::MinInt;
55

66
#[derive(Clone, Copy)]
77
enum Result {

src/float/div.rs

+60-35
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
#![allow(clippy::needless_return)]
44

55
use crate::float::Float;
6-
use crate::int::{CastInto, DInt, HInt, Int};
6+
use crate::int::{CastInto, DInt, HInt, Int, MinInt};
7+
8+
use super::HalfRep;
79

810
fn div32<F: Float>(a: F, b: F) -> F
911
where
@@ -37,6 +39,11 @@ where
3739
let quiet_bit = implicit_bit >> 1;
3840
let qnan_rep = exponent_mask | quiet_bit;
3941

42+
// #[inline(always)]
43+
// fn negate<T: Int>(a: T) -> T {
44+
// T::wrapping_neg(a.signe)
45+
// }
46+
4047
#[inline(always)]
4148
fn negate_u32(a: u32) -> u32 {
4249
(<i32>::wrapping_neg(a as i32)) as u32
@@ -459,10 +466,14 @@ where
459466
i32: CastInto<F::Int>,
460467
F::Int: CastInto<i32>,
461468
u64: CastInto<F::Int>,
469+
u64: CastInto<HalfRep<F>>,
470+
F::Int: CastInto<HalfRep<F>>,
471+
F::Int: From<HalfRep<F>>,
472+
F::Int: From<u8>,
462473
F::Int: CastInto<u64>,
463474
i64: CastInto<F::Int>,
464475
F::Int: CastInto<i64>,
465-
F::Int: HInt,
476+
F::Int: HInt + DInt,
466477
{
467478
const NUMBER_OF_HALF_ITERATIONS: usize = 3;
468479
const NUMBER_OF_FULL_ITERATIONS: usize = 1;
@@ -471,7 +482,7 @@ where
471482
let one = F::Int::ONE;
472483
let zero = F::Int::ZERO;
473484
let hw = F::BITS / 2;
474-
let lo_mask = u64::MAX >> hw;
485+
let lo_mask = F::Int::MAX >> hw;
475486

476487
let significand_bits = F::SIGNIFICAND_BITS;
477488
let max_exponent = F::EXPONENT_MAX;
@@ -616,21 +627,23 @@ where
616627

617628
let mut x_uq0 = if NUMBER_OF_HALF_ITERATIONS > 0 {
618629
// Starting with (n-1) half-width iterations
619-
let b_uq1_hw: u32 =
620-
(CastInto::<u64>::cast(b_significand) >> (significand_bits + 1 - hw)) as u32;
630+
let b_uq1_hw: HalfRep<F> = CastInto::<HalfRep<F>>::cast(
631+
CastInto::<u64>::cast(b_significand) >> (significand_bits + 1 - hw),
632+
);
621633

622634
// C is (3/4 + 1/sqrt(2)) - 1 truncated to W0 fractional bits as UQ0.HW
623635
// with W0 being either 16 or 32 and W0 <= HW.
624636
// That is, C is the aforementioned 3/4 + 1/sqrt(2) constant (from which
625637
// b/2 is subtracted to obtain x0) wrapped to [0, 1) range.
626638

627639
// HW is at least 32. Shifting into the highest bits if needed.
628-
let c_hw = (0x7504F333_u64 as u32).wrapping_shl(hw.wrapping_sub(32));
640+
let c_hw = (CastInto::<HalfRep<F>>::cast(0x7504F333_u64)).wrapping_shl(hw.wrapping_sub(32));
629641

630642
// b >= 1, thus an upper bound for 3/4 + 1/sqrt(2) - b/2 is about 0.9572,
631643
// so x0 fits to UQ0.HW without wrapping.
632-
let x_uq0_hw: u32 = {
633-
let mut x_uq0_hw: u32 = c_hw.wrapping_sub(b_uq1_hw /* exact b_hw/2 as UQ0.HW */);
644+
let x_uq0_hw: HalfRep<F> = {
645+
let mut x_uq0_hw: HalfRep<F> =
646+
c_hw.wrapping_sub(b_uq1_hw /* exact b_hw/2 as UQ0.HW */);
634647
// dbg!(x_uq0_hw);
635648
// An e_0 error is comprised of errors due to
636649
// * x0 being an inherently imprecise first approximation of 1/b_hw
@@ -661,8 +674,9 @@ where
661674
// no overflow occurred earlier: ((rep_t)x_UQ0_hw * b_UQ1_hw >> HW) is
662675
// expected to be strictly positive because b_UQ1_hw has its highest bit set
663676
// and x_UQ0_hw should be rather large (it converges to 1/2 < 1/b_hw <= 1).
664-
let corr_uq1_hw: u32 =
665-
0.wrapping_sub(((x_uq0_hw as u64).wrapping_mul(b_uq1_hw as u64)) >> hw) as u32;
677+
let corr_uq1_hw: HalfRep<F> = CastInto::<HalfRep<F>>::cast(zero.wrapping_sub(
678+
((F::Int::from(x_uq0_hw)).wrapping_mul(F::Int::from(b_uq1_hw))) >> hw,
679+
));
666680
// dbg!(corr_uq1_hw);
667681

668682
// Now, we should multiply UQ0.HW and UQ1.(HW-1) numbers, naturally
@@ -677,7 +691,9 @@ where
677691
// The fact corr_UQ1_hw was virtually round up (due to result of
678692
// multiplication being **first** truncated, then negated - to improve
679693
// error estimations) can increase x_UQ0_hw by up to 2*Ulp of x_UQ0_hw.
680-
x_uq0_hw = ((x_uq0_hw as u64).wrapping_mul(corr_uq1_hw as u64) >> (hw - 1)) as u32;
694+
x_uq0_hw = ((F::Int::from(x_uq0_hw)).wrapping_mul(F::Int::from(corr_uq1_hw))
695+
>> (hw - 1))
696+
.cast();
681697
// dbg!(x_uq0_hw);
682698
// Now, either no overflow occurred or x_UQ0_hw is 0 or 1 in its half_rep_t
683699
// representation. In the latter case, x_UQ0_hw will be either 0 or 1 after
@@ -707,7 +723,7 @@ where
707723
// be not below that value (see g(x) above), so it is safe to decrement just
708724
// once after the final iteration. On the other hand, an effective value of
709725
// divisor changes after this point (from b_hw to b), so adjust here.
710-
x_uq0_hw.wrapping_sub(1_u32)
726+
x_uq0_hw.wrapping_sub(HalfRep::<F>::ONE)
711727
};
712728

713729
// Error estimations for full-precision iterations are calculated just
@@ -717,7 +733,7 @@ where
717733
// Simulating operations on a twice_rep_t to perform a single final full-width
718734
// iteration. Using ad-hoc multiplication implementations to take advantage
719735
// of particular structure of operands.
720-
let blo: u64 = (CastInto::<u64>::cast(b_uq1)) & lo_mask;
736+
let blo: F::Int = b_uq1 & lo_mask;
721737
// x_UQ0 = x_UQ0_hw * 2^HW - 1
722738
// x_UQ0 * b_UQ1 = (x_UQ0_hw * 2^HW) * (b_UQ1_hw * 2^HW + blo) - b_UQ1
723739
//
@@ -726,19 +742,20 @@ where
726742
// + [ x_UQ0_hw * blo ]
727743
// - [ b_UQ1 ]
728744
// = [ result ][.... discarded ...]
729-
let corr_uq1 = negate_u64(
730-
(x_uq0_hw as u64) * (b_uq1_hw as u64) + (((x_uq0_hw as u64) * (blo)) >> hw) - 1,
731-
); // account for *possible* carry
732-
let lo_corr = corr_uq1 & lo_mask;
733-
let hi_corr = corr_uq1 >> hw;
745+
let corr_uq1: F::Int = (F::Int::from(x_uq0_hw) * F::Int::from(b_uq1_hw)
746+
+ ((F::Int::from(x_uq0_hw) * blo) >> hw))
747+
.wrapping_sub(one)
748+
.wrapping_neg(); // account for *possible* carry
749+
let lo_corr: F::Int = corr_uq1 & lo_mask;
750+
let hi_corr: F::Int = corr_uq1 >> hw;
734751
// x_UQ0 * corr_UQ1 = (x_UQ0_hw * 2^HW) * (hi_corr * 2^HW + lo_corr) - corr_UQ1
735-
let mut x_uq0: <F as Float>::Int = ((((x_uq0_hw as u64) * hi_corr) << 1)
736-
.wrapping_add(((x_uq0_hw as u64) * lo_corr) >> (hw - 1))
737-
.wrapping_sub(2))
738-
.cast(); // 1 to account for the highest bit of corr_UQ1 can be 1
739-
// 1 to account for possible carry
740-
// Just like the case of half-width iterations but with possibility
741-
// of overflowing by one extra Ulp of x_UQ0.
752+
let mut x_uq0: F::Int = ((F::Int::from(x_uq0_hw) * hi_corr) << 1)
753+
.wrapping_add((F::Int::from(x_uq0_hw) * lo_corr) >> (hw - 1))
754+
.wrapping_sub(F::Int::from(2u8));
755+
// 1 to account for the highest bit of corr_UQ1 can be 1
756+
// 1 to account for possible carry
757+
// Just like the case of half-width iterations but with possibility
758+
// of overflowing by one extra Ulp of x_UQ0.
742759
x_uq0 -= one;
743760
// ... and then traditional fixup by 2 should work
744761

@@ -755,8 +772,8 @@ where
755772
x_uq0
756773
} else {
757774
// C is (3/4 + 1/sqrt(2)) - 1 truncated to 64 fractional bits as UQ0.n
758-
let c: <F as Float>::Int = (0x7504F333 << (F::BITS - 32)).cast();
759-
let x_uq0: <F as Float>::Int = c.wrapping_sub(b_uq1);
775+
let c: F::Int = (0x7504F333 << (F::BITS - 32)).cast();
776+
let x_uq0: F::Int = c.wrapping_sub(b_uq1);
760777
// E_0 <= 3/4 - 1/sqrt(2) + 2 * 2^-64
761778
x_uq0
762779
};
@@ -799,14 +816,27 @@ where
799816

800817
// Add 2 to U_N due to final decrement.
801818

802-
let reciprocal_precision: <F as Float>::Int = 220.cast();
819+
let reciprocal_precision: F::Int = if F::BITS == 32
820+
&& NUMBER_OF_HALF_ITERATIONS == 2
821+
&& NUMBER_OF_FULL_ITERATIONS == 1
822+
{
823+
74.cast()
824+
} else if F::BITS == 32 && NUMBER_OF_HALF_ITERATIONS == 0 && NUMBER_OF_FULL_ITERATIONS == 3 {
825+
10.cast()
826+
} else if F::BITS == 64 && NUMBER_OF_HALF_ITERATIONS == 3 && NUMBER_OF_FULL_ITERATIONS == 1 {
827+
220.cast()
828+
} else if F::BITS == 128 && NUMBER_OF_HALF_ITERATIONS == 4 && NUMBER_OF_FULL_ITERATIONS == 1 {
829+
13922.cast()
830+
} else {
831+
panic!("invalid iterations for the specified bits");
832+
};
803833

804834
// Suppose 1/b - P * 2^-W < x < 1/b + P * 2^-W
805835
let x_uq0 = x_uq0 - reciprocal_precision;
806836
// Now 1/b - (2*P) * 2^-W < x < 1/b
807837
// FIXME Is x_UQ0 still >= 0.5?
808838

809-
let mut quotient: <F as Float>::Int = x_uq0.widen_mul(a_significand << 1).hi();
839+
let mut quotient: F::Int = x_uq0.widen_mul(a_significand << 1).hi();
810840
// Now, a/b - 4*P * 2^-W < q < a/b for q=<quotient_UQ1:dummy> in UQ1.(SB+1+W).
811841

812842
// quotient_UQ1 is in [0.5, 2.0) as UQ1.(SB+1),
@@ -914,13 +944,8 @@ intrinsics! {
914944
div64(a, b)
915945
}
916946

917-
// TODO: how should `HInt` be handled?
918947
pub extern "C" fn __divtf3(a: f128, b: f128) -> f128 {
919-
if cfg!(target_pointer_width = "64") {
920-
div32(a, b)
921-
} else {
922-
div64(a, b)
923-
}
948+
div64(a, b)
924949
}
925950

926951
#[cfg(target_arch = "arm")]

src/float/extend.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::float::Float;
2-
use crate::int::{CastInto, Int};
2+
use crate::int::{CastInto, Int, MinInt};
33

44
/// Generic conversion from a narrower to a wider IEEE-754 floating-point type
55
fn extend<F: Float, R: Float>(a: F) -> R

src/float/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ pub(crate) trait Float:
5959
/// A mask for the significand
6060
const SIGNIFICAND_MASK: Self::Int;
6161

62-
/// The implicit bit of the float format
62+
// The implicit bit of the float format
6363
const IMPLICIT_BIT: Self::Int;
6464

6565
/// A mask for the exponent

src/float/mul.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::float::Float;
2-
use crate::int::{CastInto, DInt, HInt, Int};
2+
use crate::int::{CastInto, DInt, HInt, Int, MinInt};
33

44
fn mul<F: Float>(a: F, b: F) -> F
55
where

src/float/trunc.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::float::Float;
2-
use crate::int::{CastInto, Int};
2+
use crate::int::{CastInto, Int, MinInt};
33

44
fn trunc<F: Float, R: Float>(a: F) -> R
55
where

src/int/addsub.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
use crate::int::{DInt, Int};
1+
use crate::int::{DInt, Int, MinInt};
22

3-
trait UAddSub: DInt {
3+
trait UAddSub: DInt + Int {
44
fn uadd(self, other: Self) -> Self {
55
let (lo, carry) = self.lo().overflowing_add(other.lo());
66
let hi = self.hi().wrapping_add(other.hi());
@@ -22,7 +22,7 @@ impl UAddSub for u128 {}
2222

2323
trait AddSub: Int
2424
where
25-
<Self as Int>::UnsignedInt: UAddSub,
25+
<Self as MinInt>::UnsignedInt: UAddSub,
2626
{
2727
fn add(self, other: Self) -> Self {
2828
Self::from_unsigned(self.unsigned().uadd(other.unsigned()))
@@ -37,7 +37,7 @@ impl AddSub for i128 {}
3737

3838
trait Addo: AddSub
3939
where
40-
<Self as Int>::UnsignedInt: UAddSub,
40+
<Self as MinInt>::UnsignedInt: UAddSub,
4141
{
4242
fn addo(self, other: Self) -> (Self, bool) {
4343
let sum = AddSub::add(self, other);
@@ -50,7 +50,7 @@ impl Addo for u128 {}
5050

5151
trait Subo: AddSub
5252
where
53-
<Self as Int>::UnsignedInt: UAddSub,
53+
<Self as MinInt>::UnsignedInt: UAddSub,
5454
{
5555
fn subo(self, other: Self) -> (Self, bool) {
5656
let sum = AddSub::sub(self, other);

0 commit comments

Comments
 (0)