This is my little beginner code and I do not know how to fix it.
use rug::{ Integer, Rational };
fn main() {
const N: usize = 20;
let mut c: [Rational; N];
let mut nom : Integer;
let mut denom : Integer;
denom = Integer::from(1);
for k in 1..N+1 {
denom *= Integer::from(2*k*(2*k+1));
let mut num = Rational::from((k, denom));
let mut den = Integer::from(1);
for i in 1..k {
den *= (2 * i * (2 * i + 1)) as u32;
num -= c[k - i - 1] / den;
}
c[k - 1] = num;
println!("{}", num);
}
}
use rug::{ Integer, Rational };
fn main() {
const N: usize = 20;
let mut c: [Rational; N];
let mut nom : Integer;
let mut denom : Integer;
denom = Integer::from(1);
for k in 1..N+1 {
denom *= Integer::from(2*k*(2*k+1));
let mut num = Rational::from((k, 1));
num /= &denom;
let mut den : Integer;
den = Integer::from(1);
for i in 1..k {
den *= Integer::from(2 * i * (2 * i + 1));
let mut summand : Rational;
summand = Rational::from((1, 1));
summand *= &(c[k - i - 1]);
summand /= &den;
num -= summand;
}
c[k - 1] = num;
println!("{}", num);
}
}
I played with your code a bit to make it better ("better" in a subjective sense; I hope I haven’t changed any behavior; in particular I tried to avoid some allocations by reusing variables; I’ll admit, the u16 vs usize vs u64 is a bit annoying - the idea is that u64 is large enough for multiplying u16s and u16 can be converted into usize without any possibility for failure). This is the result:
use rug::{Integer, Rational, Assign};
fn main() {
const N: u16 = 40;
let mut c: Vec<Rational> = Vec::with_capacity(N.into());
let mut summand = Rational::new();
let mut den = Integer::new();
let mut denom = Integer::from(1);
let helper_fun = |n: u64| -> u64 {2 * n * (2 * n + 1)};
for k in 1..=N {
denom *= helper_fun(k.into());
let mut num = Rational::from((k, &denom));
den.assign(1);
for i in 1..k {
den *= helper_fun(i.into());
summand.assign(&c[usize::from(k - i - 1)] / &den);
num -= &summand;
}
println!("{}", num);
c.push(num);
}
}
Thank you a lot. My initial question "is it possible without sequence on heap" (by slices instead of vectors) remains.
I played with code and obtained this:
use rug::{Integer, Rational, Assign};
fn main() {
const N: u16 = 8;
let mut c: Vec<Rational> = Vec::with_capacity(N.into());
let mut summand = Rational::new();
let mut den = Integer::new();
let mut denom = Integer::from(1);
let helper_fun = |n: u64| -> u64 {2 * n * (2 * n + 1)};
for k in 1..=N {
denom *= helper_fun(k.into());
let mut num = Rational::from((k, &denom));
den.assign(1);
for i in 1..k {
den *= helper_fun(i.into());
summand.assign(&c[usize::from(k - i - 1)] / &den);
num -= &summand;
}
c.push(Rational::from(&num));
let multiplier = Rational::from(&num).abs();
let val = f64::powf(std::f64::consts::PI, (2*k) as f64)*multiplier.to_f64();
println!("The sum of 1/n^{} when n goes from 1 to infinity is \
pi^{} times {} = 1+1/{} = {}.", 2*k, 2*k, multiplier, 1.0/(val-1.0), val);
}
}
The link @steffahn provided shows how to do it yourself (search for "Rust 1.36") or suggests a number of crates that can supply a macro to do it for you (search for "Prior Art").
I don’t see much value in avoiding the Vec since the arbitrary precision integers do way more allocation anyways. But it is possible. If you really want to avoid the vec, another drop-in replacement for the Vec, also while keeping the array on the stack would be to use the arrayvec crate.
I think the way to initialize it should look like
let mut c = ArrayVec::<[Rational; N as _]>::new();
once you add the crate dependency and import the ArrayVec type.
The rest of the code can probably stay the same as with Vec.