pub struct RnsRational {
pub numer: RnsInt,
pub denom: RnsInt,
pub channels: Channels,
/* private fields */
}Expand description
An exact rational number represented over RNS channels.
The canonical value is held as a reduced BigInt pair (p, q) so that
precision is never capped by the channel capacity — essential for the
arbitrary-precision rationals produced at Level 3. The numer/denom
RnsInt fields are the RNS view of that value (exact while the value
fits inside the channel capacity), kept for the lower-level channel-dispatch
machinery.
Fields§
§numer: RnsIntRNS view of the numerator.
denom: RnsIntRNS view of the denominator.
channels: ChannelsImplementations§
Source§impl RnsRational
impl RnsRational
Sourcepub fn new(p: BigInt, q: BigInt, channels: Channels) -> Self
pub fn new(p: BigInt, q: BigInt, channels: Channels) -> Self
Build from a p/q pair, normalizing the sign and reducing by the GCD.
Panics if q == 0.
Sourcepub fn from_fraction(p: i64, q: i64, channels: Channels) -> Self
pub fn from_fraction(p: i64, q: i64, channels: Channels) -> Self
Convenience constructor from machine integers.
Examples found in repository?
22fn main() {
23 let ch = Channels::standard(32);
24 println!("== adele-ring :: exact vs f64 ==\n");
25 println!(
26 "{:<16} | {:<10} | {:<22} | {:<12} | ULPs",
27 "expression", "exact", "f64 result", "abs error"
28 );
29 println!("{}", "-".repeat(78));
30
31 // 0.1 + 0.2 = 3/10
32 let exact = RnsRational::from_fraction(1, 10, ch.clone())
33 .add(&RnsRational::from_fraction(1, 5, ch.clone()));
34 row("0.1 + 0.2", &exact.display(), 0.1 + 0.2, exact.to_f64());
35
36 // 1/3 * 3 = 1
37 let one = RnsRational::from_fraction(1, 3, ch.clone()).mul(&RnsRational::from_int(3, ch.clone()));
38 row("1/3 * 3", &one.display(), (1.0 / 3.0) * 3.0, one.to_f64());
39
40 // sqrt(2) * sqrt(2) = 2 (drops to Integer through the tower)
41 let s2 = TowerValue::Algebraic(AlgebraicNumber::sqrt(2, ch.clone()));
42 let two = s2.mul(&s2);
43 let naive = 2f64.sqrt() * 2f64.sqrt();
44 row("sqrt2 * sqrt2", "2", naive, two.to_f64().unwrap());
45
46 // sin(pi) = 0 (exact identity; f64 gives ~1.2e-16)
47 let sin_pi = TowerValue::Symbolic(SymbolicExpr::Pi).sin();
48 row("sin(pi)", "0", std::f64::consts::PI.sin(), sin_pi.to_f64().unwrap());
49
50 // 1/7 * 7 = 1
51 let one7 = RnsRational::from_fraction(1, 7, ch.clone()).mul(&RnsRational::from_int(7, ch));
52 row("1/7 * 7", &one7.display(), (1.0 / 7.0) * 7.0, one7.to_f64());
53
54 println!("\nEvery `exact` column is bit-for-bit correct; the f64 column drifts.");
55}More examples
7fn main() {
8 let ch = Channels::standard(32);
9 let f = |p: i64, q: i64| RnsRational::from_fraction(p, q, ch.clone());
10
11 println!("== adele-ring :: exact engineering arithmetic ==\n");
12
13 // Stacked plate thicknesses in inches: 3/8 + 1/4 + 5/16.
14 let stack = f(3, 8).add(&f(1, 4)).add(&f(5, 16));
15 println!("3/8 + 1/4 + 5/16 in = {} in (= {:.6} in)", stack, stack.to_f64());
16
17 // Safety factor 1/1.5 = 2/3 exactly.
18 let safety = f(1, 1).div(&f(3, 2));
19 println!("1 / 1.5 = {} (= {:.6})", safety, safety.to_f64());
20
21 // Load ratio: 47 kips / 70 kips — stays exact through combination checks.
22 let load_ratio = f(47, 70);
23 let with_margin = load_ratio.add(&f(1, 10)); // add a 0.1 utilization margin
24 println!(
25 "47/70 + 1/10 = {} (= {:.6})",
26 with_margin,
27 with_margin.to_f64()
28 );
29
30 // AISC-style web area: t_w * d = (5/16) * (24/1) in^2.
31 let t_w = f(5, 16);
32 let d = f(24, 1);
33 let web_area = t_w.mul(&d);
34 println!("(5/16) * 24 = {} in^2 (= {:.6} in^2)", web_area, web_area.to_f64());
35
36 println!("\n-- base awareness --");
37 for (p, q) in [(1, 6), (1, 8), (47, 70)] {
38 let r = f(p, q);
39 println!(
40 "{p}/{q}: natural base = {}, terminates in base 10 = {}, period in base 10 = {}",
41 r.natural_base(),
42 r.exact_in_base(10),
43 r.termination_period_in_base(10)
44 );
45 }
46
47 // Demonstrate the classic float failure that adele-ring avoids.
48 let exact = f(1, 10).add(&f(1, 5)); // 0.1 + 0.2
49 let naive = 0.1_f64 + 0.2_f64;
50 println!("\n0.1 + 0.2 exact = {} (f64 gives {:.17})", exact, naive);
51 assert_eq!(exact, f(3, 10));
52}Sourcepub fn from_int(n: i64, channels: Channels) -> Self
pub fn from_int(n: i64, channels: Channels) -> Self
An integer rational n/1.
Examples found in repository?
22fn main() {
23 let ch = Channels::standard(32);
24 println!("== adele-ring :: exact vs f64 ==\n");
25 println!(
26 "{:<16} | {:<10} | {:<22} | {:<12} | ULPs",
27 "expression", "exact", "f64 result", "abs error"
28 );
29 println!("{}", "-".repeat(78));
30
31 // 0.1 + 0.2 = 3/10
32 let exact = RnsRational::from_fraction(1, 10, ch.clone())
33 .add(&RnsRational::from_fraction(1, 5, ch.clone()));
34 row("0.1 + 0.2", &exact.display(), 0.1 + 0.2, exact.to_f64());
35
36 // 1/3 * 3 = 1
37 let one = RnsRational::from_fraction(1, 3, ch.clone()).mul(&RnsRational::from_int(3, ch.clone()));
38 row("1/3 * 3", &one.display(), (1.0 / 3.0) * 3.0, one.to_f64());
39
40 // sqrt(2) * sqrt(2) = 2 (drops to Integer through the tower)
41 let s2 = TowerValue::Algebraic(AlgebraicNumber::sqrt(2, ch.clone()));
42 let two = s2.mul(&s2);
43 let naive = 2f64.sqrt() * 2f64.sqrt();
44 row("sqrt2 * sqrt2", "2", naive, two.to_f64().unwrap());
45
46 // sin(pi) = 0 (exact identity; f64 gives ~1.2e-16)
47 let sin_pi = TowerValue::Symbolic(SymbolicExpr::Pi).sin();
48 row("sin(pi)", "0", std::f64::consts::PI.sin(), sin_pi.to_f64().unwrap());
49
50 // 1/7 * 7 = 1
51 let one7 = RnsRational::from_fraction(1, 7, ch.clone()).mul(&RnsRational::from_int(7, ch));
52 row("1/7 * 7", &one7.display(), (1.0 / 7.0) * 7.0, one7.to_f64());
53
54 println!("\nEvery `exact` column is bit-for-bit correct; the f64 column drifts.");
55}Sourcepub fn to_pair(&self) -> (BigInt, BigInt)
pub fn to_pair(&self) -> (BigInt, BigInt)
The reduced (p, q) pair as BigInts (exact, never capacity-bounded).
Sourcepub fn is_integer(&self) -> bool
pub fn is_integer(&self) -> bool
true iff the denominator is 1 (the value is an integer).
Sourcepub fn add(&self, other: &Self) -> Self
pub fn add(&self, other: &Self) -> Self
p1/q1 + p2/q2 = (p1·q2 + p2·q1) / (q1·q2).
Examples found in repository?
22fn main() {
23 let ch = Channels::standard(32);
24 println!("== adele-ring :: exact vs f64 ==\n");
25 println!(
26 "{:<16} | {:<10} | {:<22} | {:<12} | ULPs",
27 "expression", "exact", "f64 result", "abs error"
28 );
29 println!("{}", "-".repeat(78));
30
31 // 0.1 + 0.2 = 3/10
32 let exact = RnsRational::from_fraction(1, 10, ch.clone())
33 .add(&RnsRational::from_fraction(1, 5, ch.clone()));
34 row("0.1 + 0.2", &exact.display(), 0.1 + 0.2, exact.to_f64());
35
36 // 1/3 * 3 = 1
37 let one = RnsRational::from_fraction(1, 3, ch.clone()).mul(&RnsRational::from_int(3, ch.clone()));
38 row("1/3 * 3", &one.display(), (1.0 / 3.0) * 3.0, one.to_f64());
39
40 // sqrt(2) * sqrt(2) = 2 (drops to Integer through the tower)
41 let s2 = TowerValue::Algebraic(AlgebraicNumber::sqrt(2, ch.clone()));
42 let two = s2.mul(&s2);
43 let naive = 2f64.sqrt() * 2f64.sqrt();
44 row("sqrt2 * sqrt2", "2", naive, two.to_f64().unwrap());
45
46 // sin(pi) = 0 (exact identity; f64 gives ~1.2e-16)
47 let sin_pi = TowerValue::Symbolic(SymbolicExpr::Pi).sin();
48 row("sin(pi)", "0", std::f64::consts::PI.sin(), sin_pi.to_f64().unwrap());
49
50 // 1/7 * 7 = 1
51 let one7 = RnsRational::from_fraction(1, 7, ch.clone()).mul(&RnsRational::from_int(7, ch));
52 row("1/7 * 7", &one7.display(), (1.0 / 7.0) * 7.0, one7.to_f64());
53
54 println!("\nEvery `exact` column is bit-for-bit correct; the f64 column drifts.");
55}More examples
7fn main() {
8 let ch = Channels::standard(32);
9 let f = |p: i64, q: i64| RnsRational::from_fraction(p, q, ch.clone());
10
11 println!("== adele-ring :: exact engineering arithmetic ==\n");
12
13 // Stacked plate thicknesses in inches: 3/8 + 1/4 + 5/16.
14 let stack = f(3, 8).add(&f(1, 4)).add(&f(5, 16));
15 println!("3/8 + 1/4 + 5/16 in = {} in (= {:.6} in)", stack, stack.to_f64());
16
17 // Safety factor 1/1.5 = 2/3 exactly.
18 let safety = f(1, 1).div(&f(3, 2));
19 println!("1 / 1.5 = {} (= {:.6})", safety, safety.to_f64());
20
21 // Load ratio: 47 kips / 70 kips — stays exact through combination checks.
22 let load_ratio = f(47, 70);
23 let with_margin = load_ratio.add(&f(1, 10)); // add a 0.1 utilization margin
24 println!(
25 "47/70 + 1/10 = {} (= {:.6})",
26 with_margin,
27 with_margin.to_f64()
28 );
29
30 // AISC-style web area: t_w * d = (5/16) * (24/1) in^2.
31 let t_w = f(5, 16);
32 let d = f(24, 1);
33 let web_area = t_w.mul(&d);
34 println!("(5/16) * 24 = {} in^2 (= {:.6} in^2)", web_area, web_area.to_f64());
35
36 println!("\n-- base awareness --");
37 for (p, q) in [(1, 6), (1, 8), (47, 70)] {
38 let r = f(p, q);
39 println!(
40 "{p}/{q}: natural base = {}, terminates in base 10 = {}, period in base 10 = {}",
41 r.natural_base(),
42 r.exact_in_base(10),
43 r.termination_period_in_base(10)
44 );
45 }
46
47 // Demonstrate the classic float failure that adele-ring avoids.
48 let exact = f(1, 10).add(&f(1, 5)); // 0.1 + 0.2
49 let naive = 0.1_f64 + 0.2_f64;
50 println!("\n0.1 + 0.2 exact = {} (f64 gives {:.17})", exact, naive);
51 assert_eq!(exact, f(3, 10));
52}Sourcepub fn mul(&self, other: &Self) -> Self
pub fn mul(&self, other: &Self) -> Self
Multiplication.
Examples found in repository?
22fn main() {
23 let ch = Channels::standard(32);
24 println!("== adele-ring :: exact vs f64 ==\n");
25 println!(
26 "{:<16} | {:<10} | {:<22} | {:<12} | ULPs",
27 "expression", "exact", "f64 result", "abs error"
28 );
29 println!("{}", "-".repeat(78));
30
31 // 0.1 + 0.2 = 3/10
32 let exact = RnsRational::from_fraction(1, 10, ch.clone())
33 .add(&RnsRational::from_fraction(1, 5, ch.clone()));
34 row("0.1 + 0.2", &exact.display(), 0.1 + 0.2, exact.to_f64());
35
36 // 1/3 * 3 = 1
37 let one = RnsRational::from_fraction(1, 3, ch.clone()).mul(&RnsRational::from_int(3, ch.clone()));
38 row("1/3 * 3", &one.display(), (1.0 / 3.0) * 3.0, one.to_f64());
39
40 // sqrt(2) * sqrt(2) = 2 (drops to Integer through the tower)
41 let s2 = TowerValue::Algebraic(AlgebraicNumber::sqrt(2, ch.clone()));
42 let two = s2.mul(&s2);
43 let naive = 2f64.sqrt() * 2f64.sqrt();
44 row("sqrt2 * sqrt2", "2", naive, two.to_f64().unwrap());
45
46 // sin(pi) = 0 (exact identity; f64 gives ~1.2e-16)
47 let sin_pi = TowerValue::Symbolic(SymbolicExpr::Pi).sin();
48 row("sin(pi)", "0", std::f64::consts::PI.sin(), sin_pi.to_f64().unwrap());
49
50 // 1/7 * 7 = 1
51 let one7 = RnsRational::from_fraction(1, 7, ch.clone()).mul(&RnsRational::from_int(7, ch));
52 row("1/7 * 7", &one7.display(), (1.0 / 7.0) * 7.0, one7.to_f64());
53
54 println!("\nEvery `exact` column is bit-for-bit correct; the f64 column drifts.");
55}More examples
7fn main() {
8 let ch = Channels::standard(32);
9 let f = |p: i64, q: i64| RnsRational::from_fraction(p, q, ch.clone());
10
11 println!("== adele-ring :: exact engineering arithmetic ==\n");
12
13 // Stacked plate thicknesses in inches: 3/8 + 1/4 + 5/16.
14 let stack = f(3, 8).add(&f(1, 4)).add(&f(5, 16));
15 println!("3/8 + 1/4 + 5/16 in = {} in (= {:.6} in)", stack, stack.to_f64());
16
17 // Safety factor 1/1.5 = 2/3 exactly.
18 let safety = f(1, 1).div(&f(3, 2));
19 println!("1 / 1.5 = {} (= {:.6})", safety, safety.to_f64());
20
21 // Load ratio: 47 kips / 70 kips — stays exact through combination checks.
22 let load_ratio = f(47, 70);
23 let with_margin = load_ratio.add(&f(1, 10)); // add a 0.1 utilization margin
24 println!(
25 "47/70 + 1/10 = {} (= {:.6})",
26 with_margin,
27 with_margin.to_f64()
28 );
29
30 // AISC-style web area: t_w * d = (5/16) * (24/1) in^2.
31 let t_w = f(5, 16);
32 let d = f(24, 1);
33 let web_area = t_w.mul(&d);
34 println!("(5/16) * 24 = {} in^2 (= {:.6} in^2)", web_area, web_area.to_f64());
35
36 println!("\n-- base awareness --");
37 for (p, q) in [(1, 6), (1, 8), (47, 70)] {
38 let r = f(p, q);
39 println!(
40 "{p}/{q}: natural base = {}, terminates in base 10 = {}, period in base 10 = {}",
41 r.natural_base(),
42 r.exact_in_base(10),
43 r.termination_period_in_base(10)
44 );
45 }
46
47 // Demonstrate the classic float failure that adele-ring avoids.
48 let exact = f(1, 10).add(&f(1, 5)); // 0.1 + 0.2
49 let naive = 0.1_f64 + 0.2_f64;
50 println!("\n0.1 + 0.2 exact = {} (f64 gives {:.17})", exact, naive);
51 assert_eq!(exact, f(3, 10));
52}Sourcepub fn div(&self, other: &Self) -> Self
pub fn div(&self, other: &Self) -> Self
Division. Panics if other is zero.
Examples found in repository?
7fn main() {
8 let ch = Channels::standard(32);
9 let f = |p: i64, q: i64| RnsRational::from_fraction(p, q, ch.clone());
10
11 println!("== adele-ring :: exact engineering arithmetic ==\n");
12
13 // Stacked plate thicknesses in inches: 3/8 + 1/4 + 5/16.
14 let stack = f(3, 8).add(&f(1, 4)).add(&f(5, 16));
15 println!("3/8 + 1/4 + 5/16 in = {} in (= {:.6} in)", stack, stack.to_f64());
16
17 // Safety factor 1/1.5 = 2/3 exactly.
18 let safety = f(1, 1).div(&f(3, 2));
19 println!("1 / 1.5 = {} (= {:.6})", safety, safety.to_f64());
20
21 // Load ratio: 47 kips / 70 kips — stays exact through combination checks.
22 let load_ratio = f(47, 70);
23 let with_margin = load_ratio.add(&f(1, 10)); // add a 0.1 utilization margin
24 println!(
25 "47/70 + 1/10 = {} (= {:.6})",
26 with_margin,
27 with_margin.to_f64()
28 );
29
30 // AISC-style web area: t_w * d = (5/16) * (24/1) in^2.
31 let t_w = f(5, 16);
32 let d = f(24, 1);
33 let web_area = t_w.mul(&d);
34 println!("(5/16) * 24 = {} in^2 (= {:.6} in^2)", web_area, web_area.to_f64());
35
36 println!("\n-- base awareness --");
37 for (p, q) in [(1, 6), (1, 8), (47, 70)] {
38 let r = f(p, q);
39 println!(
40 "{p}/{q}: natural base = {}, terminates in base 10 = {}, period in base 10 = {}",
41 r.natural_base(),
42 r.exact_in_base(10),
43 r.termination_period_in_base(10)
44 );
45 }
46
47 // Demonstrate the classic float failure that adele-ring avoids.
48 let exact = f(1, 10).add(&f(1, 5)); // 0.1 + 0.2
49 let naive = 0.1_f64 + 0.2_f64;
50 println!("\n0.1 + 0.2 exact = {} (f64 gives {:.17})", exact, naive);
51 assert_eq!(exact, f(3, 10));
52}Sourcepub fn denom_prime_signature(&self) -> Vec<u64>
pub fn denom_prime_signature(&self) -> Vec<u64>
The distinct primes appearing in the reduced denominator.
Sourcepub fn exact_in_base(&self, base: u64) -> bool
pub fn exact_in_base(&self, base: u64) -> bool
true iff this fraction has a terminating expansion in base, i.e. every
prime in the denominator divides base.
Examples found in repository?
7fn main() {
8 let ch = Channels::standard(32);
9 let f = |p: i64, q: i64| RnsRational::from_fraction(p, q, ch.clone());
10
11 println!("== adele-ring :: exact engineering arithmetic ==\n");
12
13 // Stacked plate thicknesses in inches: 3/8 + 1/4 + 5/16.
14 let stack = f(3, 8).add(&f(1, 4)).add(&f(5, 16));
15 println!("3/8 + 1/4 + 5/16 in = {} in (= {:.6} in)", stack, stack.to_f64());
16
17 // Safety factor 1/1.5 = 2/3 exactly.
18 let safety = f(1, 1).div(&f(3, 2));
19 println!("1 / 1.5 = {} (= {:.6})", safety, safety.to_f64());
20
21 // Load ratio: 47 kips / 70 kips — stays exact through combination checks.
22 let load_ratio = f(47, 70);
23 let with_margin = load_ratio.add(&f(1, 10)); // add a 0.1 utilization margin
24 println!(
25 "47/70 + 1/10 = {} (= {:.6})",
26 with_margin,
27 with_margin.to_f64()
28 );
29
30 // AISC-style web area: t_w * d = (5/16) * (24/1) in^2.
31 let t_w = f(5, 16);
32 let d = f(24, 1);
33 let web_area = t_w.mul(&d);
34 println!("(5/16) * 24 = {} in^2 (= {:.6} in^2)", web_area, web_area.to_f64());
35
36 println!("\n-- base awareness --");
37 for (p, q) in [(1, 6), (1, 8), (47, 70)] {
38 let r = f(p, q);
39 println!(
40 "{p}/{q}: natural base = {}, terminates in base 10 = {}, period in base 10 = {}",
41 r.natural_base(),
42 r.exact_in_base(10),
43 r.termination_period_in_base(10)
44 );
45 }
46
47 // Demonstrate the classic float failure that adele-ring avoids.
48 let exact = f(1, 10).add(&f(1, 5)); // 0.1 + 0.2
49 let naive = 0.1_f64 + 0.2_f64;
50 println!("\n0.1 + 0.2 exact = {} (f64 gives {:.17})", exact, naive);
51 assert_eq!(exact, f(3, 10));
52}Sourcepub fn natural_base(&self) -> u64
pub fn natural_base(&self) -> u64
Minimal base for an exact (terminating) representation = radical(denom).
Examples found in repository?
7fn main() {
8 let ch = Channels::standard(32);
9 let f = |p: i64, q: i64| RnsRational::from_fraction(p, q, ch.clone());
10
11 println!("== adele-ring :: exact engineering arithmetic ==\n");
12
13 // Stacked plate thicknesses in inches: 3/8 + 1/4 + 5/16.
14 let stack = f(3, 8).add(&f(1, 4)).add(&f(5, 16));
15 println!("3/8 + 1/4 + 5/16 in = {} in (= {:.6} in)", stack, stack.to_f64());
16
17 // Safety factor 1/1.5 = 2/3 exactly.
18 let safety = f(1, 1).div(&f(3, 2));
19 println!("1 / 1.5 = {} (= {:.6})", safety, safety.to_f64());
20
21 // Load ratio: 47 kips / 70 kips — stays exact through combination checks.
22 let load_ratio = f(47, 70);
23 let with_margin = load_ratio.add(&f(1, 10)); // add a 0.1 utilization margin
24 println!(
25 "47/70 + 1/10 = {} (= {:.6})",
26 with_margin,
27 with_margin.to_f64()
28 );
29
30 // AISC-style web area: t_w * d = (5/16) * (24/1) in^2.
31 let t_w = f(5, 16);
32 let d = f(24, 1);
33 let web_area = t_w.mul(&d);
34 println!("(5/16) * 24 = {} in^2 (= {:.6} in^2)", web_area, web_area.to_f64());
35
36 println!("\n-- base awareness --");
37 for (p, q) in [(1, 6), (1, 8), (47, 70)] {
38 let r = f(p, q);
39 println!(
40 "{p}/{q}: natural base = {}, terminates in base 10 = {}, period in base 10 = {}",
41 r.natural_base(),
42 r.exact_in_base(10),
43 r.termination_period_in_base(10)
44 );
45 }
46
47 // Demonstrate the classic float failure that adele-ring avoids.
48 let exact = f(1, 10).add(&f(1, 5)); // 0.1 + 0.2
49 let naive = 0.1_f64 + 0.2_f64;
50 println!("\n0.1 + 0.2 exact = {} (f64 gives {:.17})", exact, naive);
51 assert_eq!(exact, f(3, 10));
52}Sourcepub fn termination_period_in_base(&self, base: u64) -> u64
pub fn termination_period_in_base(&self, base: u64) -> u64
Repeating period in base: 0 if it terminates, else the period length.
Examples found in repository?
7fn main() {
8 let ch = Channels::standard(32);
9 let f = |p: i64, q: i64| RnsRational::from_fraction(p, q, ch.clone());
10
11 println!("== adele-ring :: exact engineering arithmetic ==\n");
12
13 // Stacked plate thicknesses in inches: 3/8 + 1/4 + 5/16.
14 let stack = f(3, 8).add(&f(1, 4)).add(&f(5, 16));
15 println!("3/8 + 1/4 + 5/16 in = {} in (= {:.6} in)", stack, stack.to_f64());
16
17 // Safety factor 1/1.5 = 2/3 exactly.
18 let safety = f(1, 1).div(&f(3, 2));
19 println!("1 / 1.5 = {} (= {:.6})", safety, safety.to_f64());
20
21 // Load ratio: 47 kips / 70 kips — stays exact through combination checks.
22 let load_ratio = f(47, 70);
23 let with_margin = load_ratio.add(&f(1, 10)); // add a 0.1 utilization margin
24 println!(
25 "47/70 + 1/10 = {} (= {:.6})",
26 with_margin,
27 with_margin.to_f64()
28 );
29
30 // AISC-style web area: t_w * d = (5/16) * (24/1) in^2.
31 let t_w = f(5, 16);
32 let d = f(24, 1);
33 let web_area = t_w.mul(&d);
34 println!("(5/16) * 24 = {} in^2 (= {:.6} in^2)", web_area, web_area.to_f64());
35
36 println!("\n-- base awareness --");
37 for (p, q) in [(1, 6), (1, 8), (47, 70)] {
38 let r = f(p, q);
39 println!(
40 "{p}/{q}: natural base = {}, terminates in base 10 = {}, period in base 10 = {}",
41 r.natural_base(),
42 r.exact_in_base(10),
43 r.termination_period_in_base(10)
44 );
45 }
46
47 // Demonstrate the classic float failure that adele-ring avoids.
48 let exact = f(1, 10).add(&f(1, 5)); // 0.1 + 0.2
49 let naive = 0.1_f64 + 0.2_f64;
50 println!("\n0.1 + 0.2 exact = {} (f64 gives {:.17})", exact, naive);
51 assert_eq!(exact, f(3, 10));
52}Sourcepub fn to_f64(&self) -> f64
pub fn to_f64(&self) -> f64
Lossy f64 approximation.
Computed via bit-shift scaling so it stays finite even when the numerator
and denominator are far too large to fit in an f64 individually.
Examples found in repository?
22fn main() {
23 let ch = Channels::standard(32);
24 println!("== adele-ring :: exact vs f64 ==\n");
25 println!(
26 "{:<16} | {:<10} | {:<22} | {:<12} | ULPs",
27 "expression", "exact", "f64 result", "abs error"
28 );
29 println!("{}", "-".repeat(78));
30
31 // 0.1 + 0.2 = 3/10
32 let exact = RnsRational::from_fraction(1, 10, ch.clone())
33 .add(&RnsRational::from_fraction(1, 5, ch.clone()));
34 row("0.1 + 0.2", &exact.display(), 0.1 + 0.2, exact.to_f64());
35
36 // 1/3 * 3 = 1
37 let one = RnsRational::from_fraction(1, 3, ch.clone()).mul(&RnsRational::from_int(3, ch.clone()));
38 row("1/3 * 3", &one.display(), (1.0 / 3.0) * 3.0, one.to_f64());
39
40 // sqrt(2) * sqrt(2) = 2 (drops to Integer through the tower)
41 let s2 = TowerValue::Algebraic(AlgebraicNumber::sqrt(2, ch.clone()));
42 let two = s2.mul(&s2);
43 let naive = 2f64.sqrt() * 2f64.sqrt();
44 row("sqrt2 * sqrt2", "2", naive, two.to_f64().unwrap());
45
46 // sin(pi) = 0 (exact identity; f64 gives ~1.2e-16)
47 let sin_pi = TowerValue::Symbolic(SymbolicExpr::Pi).sin();
48 row("sin(pi)", "0", std::f64::consts::PI.sin(), sin_pi.to_f64().unwrap());
49
50 // 1/7 * 7 = 1
51 let one7 = RnsRational::from_fraction(1, 7, ch.clone()).mul(&RnsRational::from_int(7, ch));
52 row("1/7 * 7", &one7.display(), (1.0 / 7.0) * 7.0, one7.to_f64());
53
54 println!("\nEvery `exact` column is bit-for-bit correct; the f64 column drifts.");
55}More examples
7fn main() {
8 let ch = Channels::standard(32);
9 let f = |p: i64, q: i64| RnsRational::from_fraction(p, q, ch.clone());
10
11 println!("== adele-ring :: exact engineering arithmetic ==\n");
12
13 // Stacked plate thicknesses in inches: 3/8 + 1/4 + 5/16.
14 let stack = f(3, 8).add(&f(1, 4)).add(&f(5, 16));
15 println!("3/8 + 1/4 + 5/16 in = {} in (= {:.6} in)", stack, stack.to_f64());
16
17 // Safety factor 1/1.5 = 2/3 exactly.
18 let safety = f(1, 1).div(&f(3, 2));
19 println!("1 / 1.5 = {} (= {:.6})", safety, safety.to_f64());
20
21 // Load ratio: 47 kips / 70 kips — stays exact through combination checks.
22 let load_ratio = f(47, 70);
23 let with_margin = load_ratio.add(&f(1, 10)); // add a 0.1 utilization margin
24 println!(
25 "47/70 + 1/10 = {} (= {:.6})",
26 with_margin,
27 with_margin.to_f64()
28 );
29
30 // AISC-style web area: t_w * d = (5/16) * (24/1) in^2.
31 let t_w = f(5, 16);
32 let d = f(24, 1);
33 let web_area = t_w.mul(&d);
34 println!("(5/16) * 24 = {} in^2 (= {:.6} in^2)", web_area, web_area.to_f64());
35
36 println!("\n-- base awareness --");
37 for (p, q) in [(1, 6), (1, 8), (47, 70)] {
38 let r = f(p, q);
39 println!(
40 "{p}/{q}: natural base = {}, terminates in base 10 = {}, period in base 10 = {}",
41 r.natural_base(),
42 r.exact_in_base(10),
43 r.termination_period_in_base(10)
44 );
45 }
46
47 // Demonstrate the classic float failure that adele-ring avoids.
48 let exact = f(1, 10).add(&f(1, 5)); // 0.1 + 0.2
49 let naive = 0.1_f64 + 0.2_f64;
50 println!("\n0.1 + 0.2 exact = {} (f64 gives {:.17})", exact, naive);
51 assert_eq!(exact, f(3, 10));
52}Sourcepub fn from_f64(x: f64, channels: Channels) -> Self
pub fn from_f64(x: f64, channels: Channels) -> Self
Exact dyadic rational equal to a finite f64.
Sourcepub fn to_f64_with_error(&self) -> (f64, RnsRational)
pub fn to_f64_with_error(&self) -> (f64, RnsRational)
f64 approximation together with the exact representation error
self - f64(self) as an RnsRational.
Sourcepub fn display(&self) -> String
pub fn display(&self) -> String
Human-readable form: "3/7", or just "5" when the denominator is 1.
Examples found in repository?
22fn main() {
23 let ch = Channels::standard(32);
24 println!("== adele-ring :: exact vs f64 ==\n");
25 println!(
26 "{:<16} | {:<10} | {:<22} | {:<12} | ULPs",
27 "expression", "exact", "f64 result", "abs error"
28 );
29 println!("{}", "-".repeat(78));
30
31 // 0.1 + 0.2 = 3/10
32 let exact = RnsRational::from_fraction(1, 10, ch.clone())
33 .add(&RnsRational::from_fraction(1, 5, ch.clone()));
34 row("0.1 + 0.2", &exact.display(), 0.1 + 0.2, exact.to_f64());
35
36 // 1/3 * 3 = 1
37 let one = RnsRational::from_fraction(1, 3, ch.clone()).mul(&RnsRational::from_int(3, ch.clone()));
38 row("1/3 * 3", &one.display(), (1.0 / 3.0) * 3.0, one.to_f64());
39
40 // sqrt(2) * sqrt(2) = 2 (drops to Integer through the tower)
41 let s2 = TowerValue::Algebraic(AlgebraicNumber::sqrt(2, ch.clone()));
42 let two = s2.mul(&s2);
43 let naive = 2f64.sqrt() * 2f64.sqrt();
44 row("sqrt2 * sqrt2", "2", naive, two.to_f64().unwrap());
45
46 // sin(pi) = 0 (exact identity; f64 gives ~1.2e-16)
47 let sin_pi = TowerValue::Symbolic(SymbolicExpr::Pi).sin();
48 row("sin(pi)", "0", std::f64::consts::PI.sin(), sin_pi.to_f64().unwrap());
49
50 // 1/7 * 7 = 1
51 let one7 = RnsRational::from_fraction(1, 7, ch.clone()).mul(&RnsRational::from_int(7, ch));
52 row("1/7 * 7", &one7.display(), (1.0 / 7.0) * 7.0, one7.to_f64());
53
54 println!("\nEvery `exact` column is bit-for-bit correct; the f64 column drifts.");
55}Trait Implementations§
Source§impl Clone for RnsRational
impl Clone for RnsRational
Source§fn clone(&self) -> RnsRational
fn clone(&self) -> RnsRational
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl Debug for RnsRational
impl Debug for RnsRational
Source§impl Display for RnsRational
impl Display for RnsRational
impl Eq for RnsRational
Source§impl Ord for RnsRational
impl Ord for RnsRational
1.21.0 (const: unstable) · Source§fn max(self, other: Self) -> Selfwhere
Self: Sized,
fn max(self, other: Self) -> Selfwhere
Self: Sized,
Source§impl PartialEq for RnsRational
impl PartialEq for RnsRational
Auto Trait Implementations§
impl Freeze for RnsRational
impl RefUnwindSafe for RnsRational
impl Send for RnsRational
impl Sync for RnsRational
impl Unpin for RnsRational
impl UnsafeUnpin for RnsRational
impl UnwindSafe for RnsRational
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<Q, K> Comparable<K> for Q
impl<Q, K> Comparable<K> for Q
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
key and return true if they are equal.Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more