Как напечатать число с плавающей точкой Rust со всей доступной точностью?

Я реализую алгоритм CORDIC для sin тригонометрическая функция. Чтобы сделать это, мне нужно жестко закодировать / вычислить кучу значений арктангенса. Прямо сейчас моя функция, кажется, работает (как подтверждено Wolfram Alpha) с точностью, которая напечатана, но я хотел бы иметь возможность печатать все 32 бита точности моего f32, Как я могу это сделать?

fn generate_table() {
    let pi: f32 = 3.1415926536897932384626;
    let k1: f32 = 0.6072529350088812561694; // 1/k
    let num_bits: uint = 32;
    let num_elms: uint = num_bits;
    let mul: uint = 1 << (num_bits - 2);

    println!("Cordic sin in rust");
    println!("num bits {}", num_bits);
    println!("pi is {}", pi);
    println!("k1 is {}", k1);

    let shift: f32 = 2.0;
    for ii in range(0, num_bits) {
        let ipow: f32 = 1.0 / shift.powi(ii as i32);
        let cur: f32 = ipow.atan();
        println!("table values {}", cur);
    }
}

6 ответов

Решение

Используйте спецификатор формата точности; . сопровождаемое количеством десятичных знаков точности, которые вы хотели бы видеть:

fn main() {
    let pi: f32 = 3.1415926536897932384626;
    let k1: f32 = 0.6072529350088812561694; // 1/k

    println!("pi is {:.32}", pi);
    println!("k1 is {:.32}", k1);
}

Я выбрал 32, что больше, чем число десятичных знаков в любом из этих f32s.

pi is 3.14159274101257324218750000000000
k1 is 0.60725295543670654296875000000000

Обратите внимание, что значения больше не совпадают; Значения с плавающей запятой сложны! Как уже упоминалось в комментарии, вы можете печатать как шестнадцатеричные или даже использовать свои литералы как шестнадцатеричные.

Использование точного формата спецификатора является правильным ответом, но для печати всей доступной точности просто воздержитесь от указания количества отображаемых цифр:

// prints 1
println!("{:.}", 1_f64);

// prints 0.000000000000000000000000123
println!("{:.}", 0.000000000000000000000000123_f64); 

Таким образом, вы не будете усекать значения и не будете обрезать лишние нули, и отображение будет корректным для всех значений, независимо от того, являются они очень большими или очень маленькими.

Пример детской площадки

Для полноты спецификатор формата точности также поддерживает указание фиксированной точности (согласно принятому ответу):

// prints 1.0000
println!("{:.4}", 1_f64);

а также точность, указанная во время выполнения (необязательно const, конечно):

// prints 1.00
const PRECISION: usize = 2;
println!("{:.*}", PRECISION, 1_f64); // precision specifier immediately precedes positional argument

Этот ответ был написан для Rust 0.12.0 и не относится к Rust 1.x.


Вы можете использовать to_string функция в std::f32 (не путать с to_string метод):

fn main() {
    println!("{}", std::f32::to_string(unsafe { std::mem::transmute::<i32, f32>(1) }));
    println!("{}", std::f32::to_string(unsafe { std::mem::transmute::<i32, f32>(16) }));
    println!("{}", std::f32::to_string(std::f32::MIN_POS_VALUE));
    println!("{}", std::f32::to_string(std::f32::MAX_VALUE));
    println!("{}", std::f32::to_string(std::f32::consts::PI));
}

Выход:

0.00000000000000000000000000000000000000000000140129852294921875
0.000000000000000000000000000000000000000000022420775890350341796875
0.000000000000000000000000000000000000011754944324493408203125
340282368002860660002286082464244022240
3.1415927410125732421875

Этот ответ был написан для Rust 0.12.0 и не относится к Rust 1.x.


Ты можешь использовать std::f32::to_string распечатать все цифры.

use std::f32;

fn main() {
    let pi: f32 = 3.1415926536897932384626;
    let k1: f32 = 0.6072529350088812561694; // 1/k

    println!("pi is {}", f32::to_string(pi));
    println!("k1 is {}", f32::to_string(k1));
}

Выход:

pi is 3.1415927410125732421875
k1 is 0.607252979278564453125

Чтобы обрезать конечные нули и точки, вы можете сделать:

      println!(
  "number = {}",
  format!("{:.2}", x).trim_end_matches(['.', '0'])
);

Примеры:

ИМХО нет способа обойти ящик bigdecimal, если вы хотите хранить числа с плавающей запятой с высокой точностью:

      use bigdecimal::BigDecimal;

fn main() {
    let pi = BigDecimal::parse_bytes(b"3.1415926536897932384626", 10);
    let k1 = BigDecimal::parse_bytes(b"0.6072529350088812561694", 10);  // 1/k

    println!("pi is {pi:?}");
    println!("k1 is {k1:?}");
}

получает:
pi is Some(BigDecimal("3.1415926536897932384626"))
k1 is Some(BigDecimal("0.6072529350088812561694"))

Другие вопросы по тегам