Skip to content

Commit da996d1

Browse files
bors[bot]notoria
andauthored
Merge #163
163: Extended the result of to_f32/to_f64 with infinity r=cuviper a=notoria Co-authored-by: notoria <notoria@users.noreply.github.com>
2 parents 7562ab2 + 6f5f6d7 commit da996d1

File tree

4 files changed

+89
-66
lines changed

4 files changed

+89
-66
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ categories = [ "algorithms", "data-structures", "science" ]
88
license = "MIT/Apache-2.0"
99
name = "num-bigint"
1010
repository = "https://github.com/rust-num/num-bigint"
11-
version = "0.3.0"
11+
version = "0.3.1"
1212
readme = "README.md"
1313
build = "build.rs"
1414
exclude = ["/bors.toml", "/ci/*", "/.github/*"]

src/biguint.rs

Lines changed: 46 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1687,19 +1687,22 @@ impl Roots for BigUint {
16871687
let max_bits = bits / n64 + 1;
16881688

16891689
#[cfg(feature = "std")]
1690-
let guess = if let Some(f) = self.to_f64() {
1691-
// We fit in `f64` (lossy), so get a better initial guess from that.
1692-
BigUint::from_f64((f.ln() / f64::from(n)).exp()).unwrap()
1693-
} else {
1694-
// Try to guess by scaling down such that it does fit in `f64`.
1695-
// With some (x * 2ⁿᵏ), its nth root ≈ (ⁿ√x * 2ᵏ)
1696-
let extra_bits = bits - (f64::MAX_EXP as u64 - 1);
1697-
let root_scale = extra_bits.div_ceil(&n64);
1698-
let scale = root_scale * n64;
1699-
if scale < bits && bits - scale > n64 {
1700-
(self >> scale).nth_root(n) << root_scale
1701-
} else {
1702-
BigUint::one() << max_bits
1690+
let guess = match self.to_f64() {
1691+
Some(f) if f.is_finite() => {
1692+
// We fit in `f64` (lossy), so get a better initial guess from that.
1693+
BigUint::from_f64((f.ln() / f64::from(n)).exp()).unwrap()
1694+
}
1695+
_ => {
1696+
// Try to guess by scaling down such that it does fit in `f64`.
1697+
// With some (x * 2ⁿᵏ), its nth root ≈ (ⁿ√x * 2ᵏ)
1698+
let extra_bits = bits - (f64::MAX_EXP as u64 - 1);
1699+
let root_scale = extra_bits.div_ceil(&n64);
1700+
let scale = root_scale * n64;
1701+
if scale < bits && bits - scale > n64 {
1702+
(self >> scale).nth_root(n) << root_scale
1703+
} else {
1704+
BigUint::one() << max_bits
1705+
}
17031706
}
17041707
};
17051708

@@ -1730,16 +1733,19 @@ impl Roots for BigUint {
17301733
let max_bits = bits / 2 + 1;
17311734

17321735
#[cfg(feature = "std")]
1733-
let guess = if let Some(f) = self.to_f64() {
1734-
// We fit in `f64` (lossy), so get a better initial guess from that.
1735-
BigUint::from_f64(f.sqrt()).unwrap()
1736-
} else {
1737-
// Try to guess by scaling down such that it does fit in `f64`.
1738-
// With some (x * 2²ᵏ), its sqrt ≈ (√x * 2ᵏ)
1739-
let extra_bits = bits - (f64::MAX_EXP as u64 - 1);
1740-
let root_scale = (extra_bits + 1) / 2;
1741-
let scale = root_scale * 2;
1742-
(self >> scale).sqrt() << root_scale
1736+
let guess = match self.to_f64() {
1737+
Some(f) if f.is_finite() => {
1738+
// We fit in `f64` (lossy), so get a better initial guess from that.
1739+
BigUint::from_f64(f.sqrt()).unwrap()
1740+
}
1741+
_ => {
1742+
// Try to guess by scaling down such that it does fit in `f64`.
1743+
// With some (x * 2²ᵏ), its sqrt ≈ (√x * 2ᵏ)
1744+
let extra_bits = bits - (f64::MAX_EXP as u64 - 1);
1745+
let root_scale = (extra_bits + 1) / 2;
1746+
let scale = root_scale * 2;
1747+
(self >> scale).sqrt() << root_scale
1748+
}
17431749
};
17441750

17451751
#[cfg(not(feature = "std"))]
@@ -1766,16 +1772,19 @@ impl Roots for BigUint {
17661772
let max_bits = bits / 3 + 1;
17671773

17681774
#[cfg(feature = "std")]
1769-
let guess = if let Some(f) = self.to_f64() {
1770-
// We fit in `f64` (lossy), so get a better initial guess from that.
1771-
BigUint::from_f64(f.cbrt()).unwrap()
1772-
} else {
1773-
// Try to guess by scaling down such that it does fit in `f64`.
1774-
// With some (x * 2³ᵏ), its cbrt ≈ (∛x * 2ᵏ)
1775-
let extra_bits = bits - (f64::MAX_EXP as u64 - 1);
1776-
let root_scale = (extra_bits + 2) / 3;
1777-
let scale = root_scale * 3;
1778-
(self >> scale).cbrt() << root_scale
1775+
let guess = match self.to_f64() {
1776+
Some(f) if f.is_finite() => {
1777+
// We fit in `f64` (lossy), so get a better initial guess from that.
1778+
BigUint::from_f64(f.cbrt()).unwrap()
1779+
}
1780+
_ => {
1781+
// Try to guess by scaling down such that it does fit in `f64`.
1782+
// With some (x * 2³ᵏ), its cbrt ≈ (∛x * 2ᵏ)
1783+
let extra_bits = bits - (f64::MAX_EXP as u64 - 1);
1784+
let root_scale = (extra_bits + 2) / 3;
1785+
let scale = root_scale * 3;
1786+
(self >> scale).cbrt() << root_scale
1787+
}
17791788
};
17801789

17811790
#[cfg(not(feature = "std"))]
@@ -1870,14 +1879,9 @@ impl ToPrimitive for BigUint {
18701879
let exponent = self.bits() - u64::from(fls(mantissa));
18711880

18721881
if exponent > f32::MAX_EXP as u64 {
1873-
None
1882+
Some(f32::INFINITY)
18741883
} else {
1875-
let ret = (mantissa as f32) * 2.0f32.powi(exponent as i32);
1876-
if ret.is_infinite() {
1877-
None
1878-
} else {
1879-
Some(ret)
1880-
}
1884+
Some((mantissa as f32) * 2.0f32.powi(exponent as i32))
18811885
}
18821886
}
18831887

@@ -1887,14 +1891,9 @@ impl ToPrimitive for BigUint {
18871891
let exponent = self.bits() - u64::from(fls(mantissa));
18881892

18891893
if exponent > f64::MAX_EXP as u64 {
1890-
None
1894+
Some(f64::INFINITY)
18911895
} else {
1892-
let ret = (mantissa as f64) * 2.0f64.powi(exponent as i32);
1893-
if ret.is_infinite() {
1894-
None
1895-
} else {
1896-
Some(ret)
1897-
}
1896+
Some((mantissa as f64) * 2.0f64.powi(exponent as i32))
18981897
}
18991898
}
19001899
}

tests/bigint.rs

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -448,14 +448,23 @@ fn test_convert_f32() {
448448
// largest BigInt that will round to a finite f32 value
449449
let big_num = (BigInt::one() << 128u8) - 1u8 - (BigInt::one() << (128u8 - 25));
450450
assert_eq!(big_num.to_f32(), Some(f32::MAX));
451-
assert_eq!((&big_num + 1u8).to_f32(), None);
451+
assert_eq!((&big_num + 1u8).to_f32(), Some(f32::INFINITY));
452452
assert_eq!((-&big_num).to_f32(), Some(f32::MIN));
453-
assert_eq!(((-&big_num) - 1u8).to_f32(), None);
453+
assert_eq!(((-&big_num) - 1u8).to_f32(), Some(f32::NEG_INFINITY));
454454

455-
assert_eq!(((BigInt::one() << 128u8) - 1u8).to_f32(), None);
456-
assert_eq!((BigInt::one() << 128u8).to_f32(), None);
457-
assert_eq!((-((BigInt::one() << 128u8) - 1u8)).to_f32(), None);
458-
assert_eq!((-(BigInt::one() << 128u8)).to_f32(), None);
455+
assert_eq!(
456+
((BigInt::one() << 128u8) - 1u8).to_f32(),
457+
Some(f32::INFINITY)
458+
);
459+
assert_eq!((BigInt::one() << 128u8).to_f32(), Some(f32::INFINITY));
460+
assert_eq!(
461+
(-((BigInt::one() << 128u8) - 1u8)).to_f32(),
462+
Some(f32::NEG_INFINITY)
463+
);
464+
assert_eq!(
465+
(-(BigInt::one() << 128u8)).to_f32(),
466+
Some(f32::NEG_INFINITY)
467+
);
459468
}
460469

461470
#[test]
@@ -529,14 +538,23 @@ fn test_convert_f64() {
529538
// largest BigInt that will round to a finite f64 value
530539
let big_num = (BigInt::one() << 1024u16) - 1u8 - (BigInt::one() << (1024u16 - 54));
531540
assert_eq!(big_num.to_f64(), Some(f64::MAX));
532-
assert_eq!((&big_num + 1u8).to_f64(), None);
541+
assert_eq!((&big_num + 1u8).to_f64(), Some(f64::INFINITY));
533542
assert_eq!((-&big_num).to_f64(), Some(f64::MIN));
534-
assert_eq!(((-&big_num) - 1u8).to_f64(), None);
543+
assert_eq!(((-&big_num) - 1u8).to_f64(), Some(f64::NEG_INFINITY));
535544

536-
assert_eq!(((BigInt::one() << 1024u16) - 1u8).to_f64(), None);
537-
assert_eq!((BigInt::one() << 1024u16).to_f64(), None);
538-
assert_eq!((-((BigInt::one() << 1024u16) - 1u8)).to_f64(), None);
539-
assert_eq!((-(BigInt::one() << 1024u16)).to_f64(), None);
545+
assert_eq!(
546+
((BigInt::one() << 1024u16) - 1u8).to_f64(),
547+
Some(f64::INFINITY)
548+
);
549+
assert_eq!((BigInt::one() << 1024u16).to_f64(), Some(f64::INFINITY));
550+
assert_eq!(
551+
(-((BigInt::one() << 1024u16) - 1u8)).to_f64(),
552+
Some(f64::NEG_INFINITY)
553+
);
554+
assert_eq!(
555+
(-(BigInt::one() << 1024u16)).to_f64(),
556+
Some(f64::NEG_INFINITY)
557+
);
540558
}
541559

542560
#[test]

tests/biguint.rs

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -673,10 +673,13 @@ fn test_convert_f32() {
673673
// largest BigUint that will round to a finite f32 value
674674
let big_num = (BigUint::one() << 128u8) - 1u8 - (BigUint::one() << (128u8 - 25));
675675
assert_eq!(big_num.to_f32(), Some(f32::MAX));
676-
assert_eq!((big_num + 1u8).to_f32(), None);
676+
assert_eq!((big_num + 1u8).to_f32(), Some(f32::INFINITY));
677677

678-
assert_eq!(((BigUint::one() << 128u8) - 1u8).to_f32(), None);
679-
assert_eq!((BigUint::one() << 128u8).to_f32(), None);
678+
assert_eq!(
679+
((BigUint::one() << 128u8) - 1u8).to_f32(),
680+
Some(f32::INFINITY)
681+
);
682+
assert_eq!((BigUint::one() << 128u8).to_f32(), Some(f32::INFINITY));
680683
}
681684

682685
#[test]
@@ -746,10 +749,13 @@ fn test_convert_f64() {
746749
// largest BigUint that will round to a finite f64 value
747750
let big_num = (BigUint::one() << 1024u16) - 1u8 - (BigUint::one() << (1024u16 - 54));
748751
assert_eq!(big_num.to_f64(), Some(f64::MAX));
749-
assert_eq!((big_num + 1u8).to_f64(), None);
752+
assert_eq!((big_num + 1u8).to_f64(), Some(f64::INFINITY));
750753

751-
assert_eq!(((BigUint::one() << 1024u16) - 1u8).to_f64(), None);
752-
assert_eq!((BigUint::one() << 1024u16).to_f64(), None);
754+
assert_eq!(
755+
((BigUint::one() << 1024u16) - 1u8).to_f64(),
756+
Some(f64::INFINITY)
757+
);
758+
assert_eq!((BigUint::one() << 1024u16).to_f64(), Some(f64::INFINITY));
753759
}
754760

755761
#[test]

0 commit comments

Comments
 (0)