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 ...
06-01-2026 08:45 AM
One of the first things I tried with Yamaeda's code is replace the format with a typecast. No crash, but faster (LabVIEW 2020)
Back in the days, I we had the factorial challenge and my version did 10000! is a few millisecond using lots of tricks (packing and convolution based multiplication, etc.). OTOH, a very trivial and literal (and much slower!) implementation was posted here long ago.
Note that my Pi approximation code was a bit complicated due to the fact that we want the best for each digit count of the numerator. It would have been simpler to find the best for each digit count of the denominator. Another problem definition would be to find all fractions that give a better approximation than any with smaller numbers, a longer list, but with simpler code..
06-01-2026 09:25 AM
@altenbach wrote:
It would have been simpler to find the best for each digit count of the denominator. .
Here's how that could look like:
06-01-2026 11:04 AM
@altenbach wrote:
@altenbach wrote:
It would have been simpler to find the best for each digit count of the denominator. .
Here's how that could look like:
Yes, you're definitely at the limit of IEEE 754 with this.
Comparison:
06-01-2026 11:04 AM - edited 06-01-2026 11:18 AM
@altenbach wrote:
@altenbach wrote:
It would have been simpler to find the best for each digit count of the denominator. .
Here's how that could look like:
Alternatively, since pi*3 < 10 you could have changed the code you already posted modified by finding the least error to pi-3 instead of pi and then simplifying the mixed fraction 3+N/D) to achieve the same results. And still the trivial approximateion 3 would be ommited as 1/7 is closer to pi-3 than 0/1.
06-01-2026 11:27 AM
@JÞB wrote:
Alternatively, since pi*3 < 10 you could have changed the code you already posted modified by finding the least error to pi-3 instead of pi and then simplifying the mixed fraction 3+N/D) to achieve the same results. And still the trivial approximateion 3 would be ommited as 1/7 is closer to pi-3 than 0/1.
Don't quite understand. Wouldn't that just be more math? My list does not have the trivial approximation because 22/7 is the best approximation with a single digits denominator.