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 15
(102 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 15
(68 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 15
(56 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 15
(48 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 15
(35 Views)