Skip to content

Instantly share code, notes, and snippets.

@nth10sd
Created September 4, 2024 00:49
Show Gist options
  • Save nth10sd/5e3e23ec3e823d0ed00c41164f221eb0 to your computer and use it in GitHub Desktop.
Save nth10sd/5e3e23ec3e823d0ed00c41164f221eb0 to your computer and use it in GitHub Desktop.
Calculations of pi approximations and their accuracies, using cargo-script (still in Rust 1.83.0 nightly as of 20240903)
### Start
# Tested on Linux only, as of 20240903, rustup required, Rust/Cargo at 1.83.0 on nightly
# Copy and paste the entire code into the terminal
export CARGO_SCRIPT_PATH=/tmp/cargo-script-"$(date -u +%Y%m%d)".rs ;
export RUSTUP_DEFAULT="$(rustup default | awk -F "-" '{ print $1 }')" ;
if [ ! "$RUSTUP_DEFAULT" = "nightly" ] ; then \
( rustup default nightly 2>&1 ) > /dev/null ;
fi ;
cat << EOF > "$CARGO_SCRIPT_PATH"
---cargo
[package]
edition = "2021"
[dependencies]
astro-float = "0.9.4"
[profile.dev]
codegen-units = 1
debug = false
lto = true
opt-level = 3
strip = true
---
fn main() {
use astro_float::{ Consts, RoundingMode, ctx::Context, expr };
let prec = 128 + 8; // 128-bit precision is needed, with a little more for buffer
let mut ctx = Context::new(
prec,
RoundingMode::ToEven,
Consts::new().expect("Constants cache initialized"),
-100000, // Exponent range from -100000 to 100000
100000
);
let actual_pi = ctx.const_pi();
let pi_3pt14 = expr!((2 * 157) / (pow(2, 2) * pow(5, 2)), &mut ctx);
println!(
"\n3.14 pi, accurate if rounded to 2 decimal places, difference is: {}%",
pi_3pt14
.sub_full_prec(&actual_pi)
.abs()
.mul_full_prec(&expr!(100, &mut ctx))
.div(&actual_pi, prec, RoundingMode::ToEven)
);
println!("{}", pi_3pt14.to_string());
println!(" 012");
println!(" 012");
let pi_22_7 = expr!(22 / 7, &mut ctx);
println!(
"\n22/7 pi, accurate if rounded to 2 decimal places, difference is: {}%",
pi_22_7
.sub_full_prec(&actual_pi)
.abs()
.mul_full_prec(&expr!(100, &mut ctx))
.div(&actual_pi, prec, RoundingMode::ToEven)
);
println!("{}", pi_22_7.to_string());
println!(" 012");
println!(" 012");
let pi_3pt142 = expr!((2 * 1571) / (pow(2, 3) * pow(5, 3)), &mut ctx);
println!(
"\n3.142 pi, accurate if rounded to 3 decimal places, difference is: {}%",
pi_3pt142
.sub_full_prec(&actual_pi)
.abs()
.mul_full_prec(&expr!(100, &mut ctx))
.div(&actual_pi, prec, RoundingMode::ToEven)
);
println!("{}", pi_3pt142.to_string());
println!(" 0123");
println!(" 0123");
let pi_355_113 = expr!(355 / 113, &mut ctx);
println!(
"\n355/113 pi, accurate if rounded to 6 decimal places, difference is: {}%",
pi_355_113
.sub_full_prec(&actual_pi)
.abs()
.mul_full_prec(&expr!(100, &mut ctx))
.div(&actual_pi, prec, RoundingMode::ToEven)
);
println!("{}", pi_355_113.to_string());
println!(" 0123456");
println!(" 0123456");
let pi_to_16_dp = expr!((2 * 29 * 1009 * 4201) / (3 * 53 * 577 * 853), &mut ctx);
println!(
concat!(
"\n245850922/78256779 pi, accurate if rounded to 16 decimal places,",
" difference is: {}%"
),
pi_to_16_dp
.sub_full_prec(&actual_pi)
.abs()
.mul_full_prec(&expr!(100, &mut ctx))
.div(&actual_pi, prec, RoundingMode::ToEven)
);
println!("{}", pi_to_16_dp.to_string());
println!(" 01234567890123456");
println!(" 1123456");
let pi_to_37_dp = expr!(
(43 * 2515283 * 145232751681480921457117807109) / (pow(2, 36) * pow(5, 37)),
&mut ctx
);
println!(
concat!(
"\n3.1415926535897932384626433832795028842 pi,",
" accurate if rounded to 37 decimal places, difference is: {}%"
),
pi_to_37_dp
.sub_full_prec(&actual_pi)
.abs()
.mul_full_prec(&expr!(100, &mut ctx))
.div(&actual_pi, prec, RoundingMode::ToEven)
);
println!("{}", pi_to_37_dp.to_string());
println!(" 01234567890123456789012345678901234567");
println!(" 1 2 31234567");
println!("\nActual pi is:");
println!("{}", actual_pi.to_string());
// Old code not using expr! macro and dealing with BigFloat manually
// This calculates pi accurately if rounded to 37 decimal places
// let mut cc = Consts::new().expect("Constants cache initialized.");
// let rm_none = RoundingMode::None;
// let p = 128 + 8; // 128-bit precision is needed, with a little more for buffer
// let prime_num_a = BigFloat::parse("11253889508596", Radix::Dec, p, rm_none,
// &mut cc);
// let prime_num_b = BigFloat::parse("12905116188545173", Radix::Dec, p, rm_none,
// &mut cc);
// let prime_num_1 = BigFloat::parse("1", Radix::Dec, p, rm_none, &mut cc);
// // (43 * 2515283) * ((11253889508596 * 12905116188545173) + 1)
// // = 108157169 * 145232751681480921457117807109
// // which is equal to 15707963267948966192313216916397514421
// let numerator = BigFloat::from_word(43 * 2515283, p).mul_full_prec(
// &prime_num_a.mul_full_prec(&prime_num_b).add_full_prec(&prime_num_1)
// );
// let two_pow_36 = u64::pow(2, 36).to_string();
// let denom_2_pow = BigFloat::parse(&two_pow_36, Radix::Dec, p, rm_none, &mut cc);
// let five_pow_19 = u64::pow(5, 19).to_string();
// let denom_5_pow_19 = BigFloat::parse(&five_pow_19, Radix::Dec, p, rm_none,
// &mut cc);
// let five_pow_18 = u64::pow(5, 18).to_string();
// let denom_5_pow_18 = BigFloat::parse(&five_pow_18, Radix::Dec, p, rm_none,
// &mut cc);
// // 2**36 * 5**19 * 5**18 = 2**36 * 5**37
// // which is equal to 5000000000000000000000000000000000000
// let denominator = denom_2_pow.mul_full_prec(&denom_5_pow_19).mul_full_prec(
// &denom_5_pow_18);
// let mut calculated_pi = numerator.div(&denominator, p, rm_none);
// // Fraction is essentially equal to
// // 31415926535897932384626433832795028842/10000000000000000000000000000000000000
// calculated_pi.set_precision(p, RoundingMode::ToEven).expect("Precision updated");
// println!("Calculated pi: \n{:.41}", calculated_pi);
// println!("{}", cc.pi(p, RoundingMode::ToEven));
// println!("Actual pi is above");
}
EOF
sleep 0.1 ;
echo -e "\n\n##### Sleep 0.1s, then start of cargo-script output #####\n"
cargo +nightly -Zscript --quiet "$CARGO_SCRIPT_PATH" ;
( rustup default "$RUSTUP_DEFAULT" 2>&1 ) > /dev/null ; # Revert to default channel
unset CARGO_SCRIPT_PATH RUSTUP_DEFAULT ;
### End
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment