LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Pi Approximation

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")

 

altenbach_0-1780256442976.png

 

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.

 

Message 11 of 21
(181 Views)

@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.

G# - Award winning reference based OOP for LV, for free! - Qestit VIPM GitHub

Qestit Systems
Certified-LabVIEW-Developer
0 Kudos
Message 12 of 21
(147 Views)

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:

Spoiler
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
...
Now a and b each have 1,600 digits, yielding a/b → 3,200 digits of π.
Spoiler

a=75772363482538542055321030167749084440832715441004837509528032268530514837571197266395785109997710107111326491569113748659328445169521264600768516727056764215194421547955055898708101280710364763502528957280665969902269119424695158105782261939465081343300448531258895160011018285188714408029624111636407797211808661876426353514121488531011966203379433174960232403069078814844708048734858063100400134608126941580869779386821136785800255744537985788178950155634416070405649496868209328705174675897831005636543951684860818963608884723745451593502975915489318757803423188982725411008967499968759630908402809530781672986151262938588458904398311045441528676223154243018407737991606293425034825035756323841336693271184495807950597812071389312736354415635672666026518464258753043999877624560643433217111077266064171382658739849744895961884597179013996601829412449785891656155571485196443174621721595819084345920890040900170809008661995139725570752636189903869662992874441706899650570585957592757942968935595831487688679801921562904312986021710915783135691394064606334193179559687821001514824502724632725942570169461162340764733065197698720313171074125404131538446139134162723110797273386117547327882430036043084901751033844526390522943180005516638760628318578382945695423403906344055334850131719192345210187029


b=24119092396003659880695014739438026445726691588541702838599748345118387555510804322741910762326149446140504761086967746675428206639484797722223629728418255777149938909134841034841079896091231581146144533957334864656480430421225894840128659314456554650219012735334894819416514436111953679389336663349641789654927380387410419698600133934239050398589129082607329993433322185186545707093132094213129877822135234704334457449289200735017529950328195806075103502963013105847285046015103089228662027451757809019353756474546556009064897157201664599659824315476301039675364952375054166377012316700124370030720066718674536084179028253211241095551587781685172242991960779295658889608399711491038541342086694731050348429970635929238360919495641341851007699079839555851023257338200474729050027379234885883832499849214874344257405443529475526453480318378075745949731767444782156637936145397392407610760131182506068438421366615929119476459606909532020691001967121034589156837246098741607820533053774053739828046192143798675472504216881562127611268415952165726667253413398707315188914088286727884601277788892613109804820058184690209257645891611090585530353329811367739089173566769938667807200236586373679612485018078632912752838074878533851417665236586248846222026480067002290780899231232188261274961988253310697179987

And here is the proof, where both were divided and verified by comparison with the actual value of π:
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 Code
Spoiler
use 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);
}
Quite simple. I’m not sure whether an equivalent library exists for LabVIEW (in VIPM).

 

0 Kudos
Message 13 of 21
(135 Views)

@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 ...

G# - Award winning reference based OOP for LV, for free! - Qestit VIPM GitHub

Qestit Systems
Certified-LabVIEW-Developer
0 Kudos
Message 14 of 21
(127 Views)

@Yamaeda wrote:

I just tried with Type cast to see the difference, and LV2019 crashes instead ...


It would be nice to have a minimal reproducible example of the crash to verify whether it still occurs in the recent LabVIEW 2026 Q1.
Andrey.
PS
In my previous comment, I had a small mistake with the length: it should be 1300 instead of 1600, but the idea is the same, unfortunately time to edit is expired.
0 Kudos
Message 15 of 21
(114 Views)

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.

 

 

SimpleFactorial.png

 

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..

0 Kudos
Message 16 of 21
(75 Views)

@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:

altenbach_0-1780323910672.png

 

0 Kudos
Message 17 of 21
(64 Views)

@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:

 


Screenshot 2026-06-01 18.01.21.png

Yes, you're definitely at the limit of IEEE 754 with this.

Comparison:

 

Screenshot 2026-06-01 18.00.30.png

 

0 Kudos
Message 18 of 21
(34 Views)

@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:

altenbach_0-1780323910672.png

 


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.


"Should be" isn't "Is" -Jay
0 Kudos
Message 19 of 21
(33 Views)

@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.

0 Kudos
Message 20 of 21
(13 Views)