05-31-2026 02:47 PM - edited 05-31-2026 02:50 PM
Over breakfast, I tweaked the code a little bit and this one does up to 7 numerator digits in a few milliseconds.
It does up to 10 numerator digits in a few seconds (each step takes about 10 longer), showing that for 9 or more digits, the rational approximation is identical to pi within DBL resolution. (e.g. for 9 digits: 245850922 / 78256779 == "piDBL")
Again, no guarantees. I am sure it can be improved... 😄
Looking at the "absolute difference" instead of "absolute (ratio-1)", but it makes no difference.
06-01-2026 03:36 AM
@altenbach wrote:
Cool!
Hey, this is 2026, so why not use a map instead of variant attributes?
On a side note, you could gain about 10-20% by just replacing the format into decimal string with a typecast. 😄
One flaw is that the third and fourth item have the same ratio
I'm just more used to Variant attributes, so instead of looking up how to to do it i went with Variants. The performance difference is very small. 🙂 I thought about Type cast but some test i did a long time ago showed surprisingly small difference, but my test might have been lacking.
Yes, i saw that the 3rd and 4th are the same, which in itself is interesting regarding which fractions do improve the result. That makes 355/113 even more impressive.
06-01-2026 04:31 AM
Here is my “breakfast contribution” to this topic — though not in LabVIEW, so sorry about that. Not entirely “mine,” to be honest — AI helped me a bit…
150 lines of source code using BigInt and BigRational:
use num_bigint::BigInt;
use num_rational::BigRational;
use num_traits::{One, Signed, Zero};
/// digits of π (public domain)
const PI_STR: &str =
"3.141592653589793238462643383279502884197169399375105820974944592307816406286\
20899862803482534211706798214808651328230664709384460955058223172535940812848\
11174502841027019385211055596446229489549303819644288109756659334461284756482\
33786783165271201909145648566923460348610454326648213393607260249141273724587\
00660631558817488152092096282925409171536436789259036001133053054882046652138\
41469519415116094330572703657595919530921861173819326117931051185480744623799\
62749567351885752724891227938183011949129833673362440656643086021394946395224\
73719070217986094370277053921717629317675238467481846766940513200056812714526\
35608277857713427577896091736371787214684409012249534301465495853710507922796\
89258923542019956112129021960864034418159813629774771309960518707211349999998\
37297804995105973173281609631859502445945534690830264252230825334468503526193\
11881710100031378387528865875332083814206171776691473035982534904287554687311\
59562863882353787593751957781857780532171226806613001927876611195909216420198\
93809525720106548586327886593615338182796823030195203530185296899577362259941\
38912497217752834791315155748572424541506959508295331168617278558890750983817\
54637464939319255060400927701671139009848824012858361603563707660104710181942\
95559619894676783744944825537977472684710404753464620804668425906949129331367\
70289891521047521620569660240580381501935112533824300355876402474964732639141\
99272604269922796782354781636009341721641219924586315030286182974555706749838\
09580358576308872929732116783372792052741906970056938105643053811371768646710\
13172452389593552420028440267543867599236615095131872257397509877818577805321\
71226806613001927876611195909216420198938095257201065485863278865936153381827\
96823030195203530185296899577362259941389124972177528347913151557485724245415\
06959508295331168617278558890750983817546374649393192550604009277016711390098\
48824012858361603563707660104710181942955596198946767837449448255379774726847\
10404753464620804668425906949129336770289891521047521620569660240580381501935\
11253382430035587640247496473263914199272604269922796782354781636009341721641\
21992458631503028618297455570674983809580358576308872929732116783372792052741\
90697005693854370070652587040859133746414428227726346594704745878477872019277\
15280731767907707157213444730605700733492436931138350493163128404251219256517\
98069411352801314701304781643788518529092854520116583934196562134914341595625\
86586557055269049652098580338507224264829397285847831630577775606888764462482\
46857926039535277348030480290058760758251047470916439613626760449256274204208\
3208566119062545433721315359584506877246029016187667952406163"; // 2600
/// Convert decimal string to exact BigRational
fn parse_decimal_to_rational(s: &str) -> BigRational {
let parts: Vec<&str> = s.split('.').collect();
if parts.len() == 1 {
return BigRational::from_integer(parts[0].parse::<BigInt>().unwrap());
}
let int_part = parts[0].parse::<BigInt>().unwrap();
let frac_part = parts[1];
let scale = BigInt::from(10u64).pow(frac_part.len() as u32);
let frac_int = frac_part.parse::<BigInt>().unwrap();
let numerator = int_part * &scale + frac_int;
BigRational::new(numerator, scale)
}
fn digit_count(n: &BigInt) -> usize {
n.to_str_radix(10).len()
}
/// Create max denominator with exactly `digits` digits
fn max_den_with_digits(digits: u32) -> BigInt {
BigInt::from(10u64).pow(digits) - BigInt::one()
}
/// Generate balanced-digit convergents of π
fn balanced_pi_convergents(max_den: &BigInt, pi: &BigRational) -> Vec<(BigInt, BigInt)> {
// Continued fraction expansion
let mut x = pi.clone();
let mut a0 = x.to_integer();
let mut cf = vec![a0.clone()];
while !x.is_integer() {
x = BigRational::from_integer(BigInt::one()) / (x - BigRational::from_integer(a0));
a0 = x.to_integer();
cf.push(a0.clone());
}
// Build convergents
let mut p0 = BigInt::one();
let mut p1 = cf[0].clone();
let mut q0 = BigInt::zero();
let mut q1 = BigInt::one();
let mut result = Vec::new();
for a in cf.iter().skip(1) {
let p = a * &p1 + &p0;
let q = a * &q1 + &q0;
if &q > max_den {
break;
}
let dp = digit_count(&p);
let dq = digit_count(&q);
if (dp as i32 - dq as i32).abs() <= 1 {
result.push((p.clone(), q.clone()));
}
p0 = p1;
p1 = p;
q0 = q1;
q1 = q;
}
result
}
/// Choose the best convergent (smallest |π - p/q|)
fn best_of_balanced(list: &[(BigInt, BigInt)], pi: &BigRational) -> (BigInt, BigInt) {
let mut best = list[0].clone();
let mut best_err = (pi.clone() - BigRational::new(best.0.clone(), best.1.clone())).abs();
for (p, q) in list.iter().skip(1) {
let r = BigRational::new(p.clone(), q.clone());
let err = (pi - &r).abs();
if err < best_err {
best = (p.clone(), q.clone());
best_err = err;
}
}
best
}
fn main() {
// Parse π once
let pi = parse_decimal_to_rational(PI_STR);
// Choose denominator size by number of digits
let max_den = max_den_with_digits(1301); // example: 1300+1-digits denominator
let conv = balanced_pi_convergents(&max_den, &pi);
println!("Balanced-digit convergents:");
for (p, q) in &conv {
println!("{}/{}", p, q);
}
let (bp, bq) = best_of_balanced(&conv, &pi);
println!("\nBest balanced convergent:");
println!("{}/{}", bp, bq);
}This gave same result as LabVIEW except 1058128194/336812665, here we have 1068966896/340262731 instead:
355/113
...
833719/265381
5419351/1725033
80143857/25510582
245850922/78256779
1068966896/340262731
The next for 11 digits:
14885392687/4738167652
...
a=75772363482538542055321030167749084440832715441004837509528032268530514837571197266395785109997710107111326491569113748659328445169521264600768516727056764215194421547955055898708101280710364763502528957280665969902269119424695158105782261939465081343300448531258895160011018285188714408029624111636407797211808661876426353514121488531011966203379433174960232403069078814844708048734858063100400134608126941580869779386821136785800255744537985788178950155634416070405649496868209328705174675897831005636543951684860818963608884723745451593502975915489318757803423188982725411008967499968759630908402809530781672986151262938588458904398311045441528676223154243018407737991606293425034825035756323841336693271184495807950597812071389312736354415635672666026518464258753043999877624560643433217111077266064171382658739849744895961884597179013996601829412449785891656155571485196443174621721595819084345920890040900170809008661995139725570752636189903869662992874441706899650570585957592757942968935595831487688679801921562904312986021710915783135691394064606334193179559687821001514824502724632725942570169461162340764733065197698720313171074125404131538446139134162723110797273386117547327882430036043084901751033844526390522943180005516638760628318578382945695423403906344055334850131719192345210187029
b=24119092396003659880695014739438026445726691588541702838599748345118387555510804322741910762326149446140504761086967746675428206639484797722223629728418255777149938909134841034841079896091231581146144533957334864656480430421225894840128659314456554650219012735334894819416514436111953679389336663349641789654927380387410419698600133934239050398589129082607329993433322185186545707093132094213129877822135234704334457449289200735017529950328195806075103502963013105847285046015103089228662027451757809019353756474546556009064897157201664599659824315476301039675364952375054166377012316700124370030720066718674536084179028253211241095551587781685172242991960779295658889608399711491038541342086694731050348429970635929238360919495641341851007699079839555851023257338200474729050027379234885883832499849214874344257405443529475526453480318378075745949731767444782156637936145397392407610760131182506068438421366615929119476459606909532020691001967121034589156837246098741607820533053774053739828046192143798675472504216881562127611268415952165726667253413398707315188914088286727884601277788892613109804820058184690209257645891611090585530353329811367739089173566769938667807200236586373679612485018078632912752838074878533851417665236586248846222026480067002290780899231232188261274961988253310697179987
fn main() {
// Huge integers a and b
let a = BigInt::from_str("757723... 1600 digits").unwrap();
let b = BigInt::from_str("241190... 1600 digits").unwrap();
let r = BigRational::new(a, b); // Compute a/b exactly
// Convert to decimal with 2600 digits
let computed = rational_to_decimal(&r, 2600);
let matches = computed == PI_STR; // Compare with PI
println!("Matches 2600-digit π: {}", matches);
}Full Source Codeuse num_bigint::BigInt;
use num_rational::BigRational;
use std::str::FromStr;
/// 2600 digits of π (your constant)
const PI_STR: &str =
"3.141592653589793238462643383279502884197169399375105820974944592307816406286\
20899862803482534211706798214808651328230664709384460955058223172535940812848\
11174502841027019385211055596446229489549303819644288109756659334461284756482\
33786783165271201909145648566923460348610454326648213393607260249141273724587\
00660631558817488152092096282925409171536436789259036001133053054882046652138\
41469519415116094330572703657595919530921861173819326117931051185480744623799\
62749567351885752724891227938183011949129833673362440656643086021394946395224\
73719070217986094370277053921717629317675238467481846766940513200056812714526\
35608277857713427577896091736371787214684409012249534301465495853710507922796\
89258923542019956112129021960864034418159813629774771309960518707211349999998\
37297804995105973173281609631859502445945534690830264252230825334468503526193\
11881710100031378387528865875332083814206171776691473035982534904287554687311\
59562863882353787593751957781857780532171226806613001927876611195909216420198\
93809525720106548586327886593615338182796823030195203530185296899577362259941\
38912497217752834791315155748572424541506959508295331168617278558890750983817\
54637464939319255060400927701671139009848824012858361603563707660104710181942\
95559619894676783744944825537977472684710404753464620804668425906949129331367\
70289891521047521620569660240580381501935112533824300355876402474964732639141\
99272604269922796782354781636009341721641219924586315030286182974555706749838\
09580358576308872929732116783372792052741906970056938105643053811371768646710\
13172452389593552420028440267543867599236615095131872257397509877818577805321\
71226806613001927876611195909216420198938095257201065485863278865936153381827\
96823030195203530185296899577362259941389124972177528347913151557485724245415\
06959508295331168617278558890750983817546374649393192550604009277016711390098\
48824012858361603563707660104710181942955596198946767837449448255379774726847\
10404753464620804668425906949129336770289891521047521620569660240580381501935\
11253382430035587640247496473263914199272604269922796782354781636009341721641\
21992458631503028618297455570674983809580358576308872929732116783372792052741\
90697005693854370070652587040859133746414428227726346594704745878477872019277\
15280731767907707157213444730605700733492436931138350493163128404251219256517\
98069411352801314701304781643788518529092854520116583934196562134914341595625\
86586557055269049652098580338507224264829397285847831630577775606888764462482\
46857926039535277348030480290058760758251047470916439613626760449256274204208\
3208566119062545433721315359584506877246029016187667952406163"; // 2600
/// Convert BigRational to decimal string with N digits after decimal
fn rational_to_decimal(r: &BigRational, digits: usize) -> String {
let num = r.numer().clone();
let den = r.denom().clone();
let ten_pow = BigInt::from(10u32).pow(digits as u32);
let scaled = num * ten_pow / den;
let s = scaled.to_str_radix(10);
let int_part = &s[..s.len() - digits];
let frac_part = &s[s.len() - digits..];
format!("{}.{}", int_part, frac_part)
}
fn main() {
// Your huge integers a and b
let a = BigInt::from_str("75772363482538542055321030167749084440832715441004837509528032268530514837571197266395785109997710107111326491569113748659328445169521264600768516727056764215194421547955055898708101280710364763502528957280665969902269119424695158105782261939465081343300448531258895160011018285188714408029624111636407797211808661876426353514121488531011966203379433174960232403069078814844708048734858063100400134608126941580869779386821136785800255744537985788178950155634416070405649496868209328705174675897831005636543951684860818963608884723745451593502975915489318757803423188982725411008967499968759630908402809530781672986151262938588458904398311045441528676223154243018407737991606293425034825035756323841336693271184495807950597812071389312736354415635672666026518464258753043999877624560643433217111077266064171382658739849744895961884597179013996601829412449785891656155571485196443174621721595819084345920890040900170809008661995139725570752636189903869662992874441706899650570585957592757942968935595831487688679801921562904312986021710915783135691394064606334193179559687821001514824502724632725942570169461162340764733065197698720313171074125404131538446139134162723110797273386117547327882430036043084901751033844526390522943180005516638760628318578382945695423403906344055334850131719192345210187029").unwrap();
let b = BigInt::from_str("24119092396003659880695014739438026445726691588541702838599748345118387555510804322741910762326149446140504761086967746675428206639484797722223629728418255777149938909134841034841079896091231581146144533957334864656480430421225894840128659314456554650219012735334894819416514436111953679389336663349641789654927380387410419698600133934239050398589129082607329993433322185186545707093132094213129877822135234704334457449289200735017529950328195806075103502963013105847285046015103089228662027451757809019353756474546556009064897157201664599659824315476301039675364952375054166377012316700124370030720066718674536084179028253211241095551587781685172242991960779295658889608399711491038541342086694731050348429970635929238360919495641341851007699079839555851023257338200474729050027379234885883832499849214874344257405443529475526453480318378075745949731767444782156637936145397392407610760131182506068438421366615929119476459606909532020691001967121034589156837246098741607820533053774053739828046192143798675472504216881562127611268415952165726667253413398707315188914088286727884601277788892613109804820058184690209257645891611090585530353329811367739089173566769938667807200236586373679612485018078632912752838074878533851417665236586248846222026480067002290780899231232188261274961988253310697179987").unwrap();
// Compute a/b exactly
let r = BigRational::new(a, b);
// Convert to decimal with 2600 digits
let computed = rational_to_decimal(&r, 2600);
println!("Original 2600-digit π: {}", PI_STR);
println!("Computed 2600-digit π: {}", computed);
// Compare with PI_STR
let matches = computed == PI_STR;
println!("Matches 2600-digit π: {}", matches);
}Everything above could be implemented in LabVIEW as well, but if I ever need this, it would be easier from both a development and execution performance point of view to wrap the necessary functions into a DLL library and then call them from LabVIEW code. A nice refresher on working with big numbers, love such small exercises.
Here is an example of how 1024! can be computed with BigInt:
use num_bigint::BigInt;
use num_traits::{One};
fn factorial(n: u64) -> BigInt {
let mut result = BigInt::one();
for i in 1..=n {
result *= i;
}
result
}
fn main() {
let n = 1024;
let fact = factorial(n);
println!("{}! = {}", n, fact);
}
06-01-2026 04:47 AM
@Yamaeda wrote:
@altenbach wrote:
Cool!
Hey, this is 2026, so why not use a map instead of variant attributes?
On a side note, you could gain about 10-20% by just replacing the format into decimal string with a typecast. 😄
One flaw is that the third and fourth item have the same ratio
I'm just more used to Variant attributes, so instead of looking up how to to do it i went with Variants. The performance difference is very small. 🙂 I thought about Type cast but some test i did a long time ago showed surprisingly small difference, but my test might have been lacking.
Yes, i saw that the 3rd and 4th are the same, which in itself is interesting regarding which fractions do improve the result. That makes 355/113 even more impressive.
I just tried with Type cast to see the difference, and LV2019 crashes instead ...
06-01-2026 05:00 AM - edited 06-01-2026 05:35 AM
@Yamaeda wrote:I just tried with Type cast to see the difference, and LV2019 crashes instead ...