我有以下生锈代码:
use std::f64::consts as f64;
fn main() {
println!("Checking f64 PI...");
// f64::PI definition: https://github.com/rust-lang/rust/blob/e1fc9ff4a794fb069d670dded1a66f05c86f3555/library/core/src/num/f64.rs#L240
println!("Definition: pub const PI: f64 = 3.14159265358979323846264338327950288_f64;");
println!("Print it: {:.35}", f64::PI);
println!("Different after 16 significant digits ----------| ");
println!("##############################################################################");
println!("Question 1: Why do the digits differ after 16 significant digits when printed?");
println!("##############################################################################");
println!("PERFORM ASSERTIONS...");
assert_eq!(f64::PI, 3.14159265358979323846264338327950288_f64); // 36 significant digits definition
assert_eq!(f64::PI, 3.141592653589793_f64); // 16 significant digits (less then the 36 in definition)
// compares up to here -------------|
assert_eq!(f64::PI, 3.14159265358979300000000000000000000_f64); // 36 significant digits (16 used in equality comparison)
assert_ne!(f64::PI, 3.14159265358979_f64); // 15 significant digits (not equal)
println!("PERFORM EQUALITY CHECK...");
if 3.14159265358979323846264338327950288_f64 == 3.14159265358979300000000000000000000_f64 {
println!("BAD: floats considered equal even when they differ past 16 significant digits");
println!("######################################################################");
println!("Question 2: Why does equality checking use only 16 significant digits?");
println!("They are defined using 36 significant digits so why can't we perform");
println!("an equality check with this accuracy?");
println!("######################################################################");
} else {
println!("GOOD: floats considered different when they differ past 16 significant digits");
println!("NOTE: This block won't execute :(");
}
}
我知道浮点运算可能很棘手,但我想知道这些技巧是否也会影响f64的打印和执行相等性检查。以下是上述代码的输出:
Checking f64 PI...
Definition: pub const PI: f64 = 3.14159265358979323846264338327950288_f64;
Print it: 3.14159265358979311599796346854418516
Different after 16 significant digits ----------|
##############################################################################
Question 1: Why do the digits differ after 16 significant digits when printed?
##############################################################################
PERFORM ASSERTIONS...
PERFORM EQUALITY CHECK...
BAD: floats considered equal even when they differ past 16 significant digits
######################################################################
Question 2: Why does equality checking use only 16 significant digits?
They are defined using 36 significant digits so why can't we perform
an equality check with this accuracy?
######################################################################
您首先假设传递所有这些双字面值3.14159265358979323846264338327950288_f64
,3.141592653589793_f64
或3.14159265358979_f64
实际上会将这些精确值分配给变量。这种假设是不正确的。
尽管rust源代码的作者使用数学常数的前36位实际数字来定义f64::PI
,但使用IEEE 754浮点格式存储的实际64位值是不同的。根据在线转换器,最接近的IEEE 754 64位浮点值将是0x400921FB542D18
,当转换回十进制时,可以使用数字3.1415926535897931159979634685
进行近似。当您将IEEE 754值0x400921FB5442D18
转换为十进制数时,会得到相同的值。
换句话说:
What we wanted to store: 3.14159265358979323846264338327950288
What is actually stored: 3.14159265358979311599796346854...
也许更简单的可视化方法是想象一个虚构的数据类型,它可以存储从0到1的正实数,并在内部使用字符串(一个字符数组)表示,最大长度为12个字符。所以,你使用这个奇怪的96位类型,创建5个变量:
strdouble A = 0.333333; // internally stored as x = { .raw = "0.333333000" }
strdouble B = 0.333333333; // internally stored as x = { .raw = "0.333333333" }
strdouble C = 0.333333333333; // internally stored as x = { .raw = "0.333333333" }
strdouble D = 0.333333333444; // internally stored as x = { .raw = "0.333333333" }
strdouble E = 0.333333333555; // internally stored as x = { .raw = "0.333333334" }
您可以看到B
、C
和D
将是相等的,尽管传递给编译器的文字值是完全不同的。您还可以看到算术(1/3 1/3 1/3)返回0.999999999
而不是1
,因为根本没有方法来表示最后一个原始数字以外的任何精度。
顾名思义,f64以64位存储。在这种固定数量的存储中,我们只能对固定数量的数字进行编码(具体来说,其中52位专用于有效位)。如果在浮点文本中使用更多数字,则存储在f64
变量中的数字将被舍入到可用位数表示的最接近的数字。对于f64
这意味着我们总是可以精确地表示15位十进制数字,有时是16位。这就解释了为什么有时候,即使在源代码中使用了不同的浮点文字,数字仍然是相等的:这是因为在四舍五入到最接近的可表示数字后,它们是相同的。
打印不同数字的原因是相同的。存储时,数字四舍五入到最接近的可表示数字,打印时再次转换回十进制。额外的数字源于二进制到十进制的转换,但小数点后15或16位的数字基本上是没有意义的——它们不携带任何有关所表示数字的额外信息。
请注意,这些都不是铁锈特有的。大多数现代编程语言使用IEEE 754-1985标准来表示浮点数,因此它们的行为相同。如果你想要任意精度的算法,你通常需要使用一些库,例如地毯板条箱。
问题内容: 我开始于: 然后尝试: 最终: 从那以后我发现: 因此,我已经解决了最初的问题(有点),但是为什么数组不能互相匹配? 问题答案: Javascript数组是对象,您不能简单地使用相等运算符来了解那些对象的 内容 是否相同。如果两个物体实际上是完全一样的情况下(如平等运营商将只测试,作品和太)。 如果您需要检查两个数组是否相等,我建议只遍历两个数组并验证所有元素具有相同的值(并且两个数组
虽然Rust中的所有整数类型都实现了强调总排序的,但浮点类型只实现了。这意味着可能存在无法比较的浮点值。这似乎很难理解,因为浮点数可以被认为是实数的近似值,实数碰巧是一个完全有序的集合。即使加上正无穷大和负无穷大,也会使实数集保持完全有序。为什么在铁锈这个奇怪的选择? 这种限制意味着通用排序/搜索算法只能假设数字的部分排序。IEEE 754标准似乎提供了一个总排序谓词。 NaN在通用代码中是个大问
如果变量值的数据类型很短,且数字为1,是否将使用16位?
问题内容: 最近,我阅读了很多有关Unicode代码点的信息,以及它们随着时间的演变,并确保我也阅读了http://www.joelonsoftware.com/articles/Unicode.html。 但是我找不到真正的原因是Java为什么将UTF-16用作字符。 例如,如果我的字符串包含1024个ASCII范围的字母。这意味着等于2KB的字符串内存,它将以任何方式消耗。 因此,如果Java
Rust的枚举是代数数据类型。据我所知,这似乎包含了struct是什么。struct有什么不同之处需要保留它?
我正在制作一个类似游戏24的程序。 我需要检查用户的输入(一个使用程序提供的四个随机数的数学方程),看看用户给出的数字是否只有一个数字。 例如: 程序吐出6 4 9 5 用户可以输入9 5 6 4(等于24)。 但是我不希望他们能够做任何像95-64这样的事情(不对,只是一个例子)来制造24。 我如何检查等式中的数字是否只有一位数? /***接受用户的数学问题。*然后...*确保输入的数学问题遵循