考虑到我们不对浮点数进行任何操作,严格比较浮点数是否安全?
Is it safe to compare floats strictly, given we do no operations on them?
通常,当我们想要测试小数是否相等时,由于 IEEE754 的近似性质,我们这样做会有一定的不确定性。
if (fabs(one_float - other_float) < SUFFICIENTLY_SMALL) {
consider them equal;
}
其他方法可能是将浮点数转换为特定大小的整数,然后比较结果整数。
if ((uint)one_float == (uint)other_float) {
consider them equal;
}
但是请考虑我们的浮点数从不进行任何算术运算的情况,我们对它们所做的唯一事情就是赋值。
// Might be called at any moment
void resize(float new_width, float new_height)
{
if (current_width == new_width && current_height == new_height) {
return;
}
accomodate framebuffers;
update uniforms;
do stuff;
current_width = new_width;
current_height = new_height;
}
在上面的示例中,我们有一个可能会自发启动的事件处理程序,并且我们希望仅在真正调整大小发生时才重新分配资源。我们可能会采用通常的方法进行近似比较,但这似乎是一种浪费,因为该处理程序会经常启动。据我所知,浮点数和其他所有东西一样,都是使用内存移动分配的;相等运算符只执行内存比较。所以看起来我们在一个安全的港湾。在 x86 和 ARM 上检查时,这个假设成立,但我只是想确定一下。也许它有一些规格支持?
那么,有没有什么东西可能只在分配时改变浮动?所描述的方法是否可行?
在这里查看如何比较两个浮点数。
https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/
找到 "ULP, he said nervously" 的测试。您可以将浮点数与整数进行比较,但看看文章中是如何完成的(我希望我没有违反此处的任何许可,如果是这样,请删除后面的代码,这不是我的代码)
bool AlmostEqualUlps(float A, float B, int maxUlpsDiff){
Float_t uA(A);
Float_t uB(B);
// Different signs means they do not match.
if (uA.Negative() != uB.Negative()) {
// Check for equality to make sure +0==-0
if (A == B) {
return true;
}
return false;
}
// Find the difference in ULPs.
int ulpsDiff = abs(uA.i - uB.i);
if (ulpsDiff <= maxUlpsDiff) {
return true;
}
return false;
}
请阅读那篇文章的其余部分,它真的很棒。
在您提到的情况下,使用 ==
进行比较是安全的,因为函数末尾有以下几行:
current_width = new_width;
current_height = new_height;
对 new_width
或 new_height
的任何更改都将使 if 语句失败,您将获得所需的行为。
abs()
函数通常用在程序中有一个动态赋值的变量float和一个常量float作为参考。类似于:
bool isEqual(float first, float second)
{
if(fabs(first-second)<0.0001)
return true;
return false;
}
int main()
{
float x = (float) 1 / 3;
if(isEqual(x,0.3333))
printf("It is equal\n");
else
printf("It is not equal\n");
}
接下来是 "should" 秒。
我认为没有任何内容表明从 float 到 float (current_width = new_width
) 的赋值不能改变值,但如果存在这样的事情我会感到惊讶。除了直接复制之外,没有理由在相同类型的变量之间进行赋值。
如果传入的 new_width
和 new_height
保持它们的值直到它们改变,那么这个比较应该没有任何问题。但是如果在每次调用之前计算它们,它们可能会改变它们的值,这取决于计算是如何完成的。所以需要检查的不仅仅是这个功能
C 2011 标准表示计算可能使用比您分配给的格式更高的精度,但没有具体说明将一个变量分配给另一个变量。所以唯一的不精确应该在计算阶段。 "simple assignment" 部分 (6.5.16.1) 说:
In simple assignment (=), the value of the right operand is converted to the type of the assignment expression and replaces the value stored in the object designated by the left operand.
所以如果类型已经匹配,应该不需要转换。
因此,简单地说:如果您不在每次调用时重新计算传入值,则相等比较 应该 成立。但是真的存在您的帧缓冲区大小为浮点数而不是整数的情况吗?
通常,当我们想要测试小数是否相等时,由于 IEEE754 的近似性质,我们这样做会有一定的不确定性。
if (fabs(one_float - other_float) < SUFFICIENTLY_SMALL) {
consider them equal;
}
其他方法可能是将浮点数转换为特定大小的整数,然后比较结果整数。
if ((uint)one_float == (uint)other_float) {
consider them equal;
}
但是请考虑我们的浮点数从不进行任何算术运算的情况,我们对它们所做的唯一事情就是赋值。
// Might be called at any moment
void resize(float new_width, float new_height)
{
if (current_width == new_width && current_height == new_height) {
return;
}
accomodate framebuffers;
update uniforms;
do stuff;
current_width = new_width;
current_height = new_height;
}
在上面的示例中,我们有一个可能会自发启动的事件处理程序,并且我们希望仅在真正调整大小发生时才重新分配资源。我们可能会采用通常的方法进行近似比较,但这似乎是一种浪费,因为该处理程序会经常启动。据我所知,浮点数和其他所有东西一样,都是使用内存移动分配的;相等运算符只执行内存比较。所以看起来我们在一个安全的港湾。在 x86 和 ARM 上检查时,这个假设成立,但我只是想确定一下。也许它有一些规格支持?
那么,有没有什么东西可能只在分配时改变浮动?所描述的方法是否可行?
在这里查看如何比较两个浮点数。
https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/
找到 "ULP, he said nervously" 的测试。您可以将浮点数与整数进行比较,但看看文章中是如何完成的(我希望我没有违反此处的任何许可,如果是这样,请删除后面的代码,这不是我的代码)
bool AlmostEqualUlps(float A, float B, int maxUlpsDiff){
Float_t uA(A);
Float_t uB(B);
// Different signs means they do not match.
if (uA.Negative() != uB.Negative()) {
// Check for equality to make sure +0==-0
if (A == B) {
return true;
}
return false;
}
// Find the difference in ULPs.
int ulpsDiff = abs(uA.i - uB.i);
if (ulpsDiff <= maxUlpsDiff) {
return true;
}
return false;
}
请阅读那篇文章的其余部分,它真的很棒。
在您提到的情况下,使用 ==
进行比较是安全的,因为函数末尾有以下几行:
current_width = new_width;
current_height = new_height;
对 new_width
或 new_height
的任何更改都将使 if 语句失败,您将获得所需的行为。
abs()
函数通常用在程序中有一个动态赋值的变量float和一个常量float作为参考。类似于:
bool isEqual(float first, float second)
{
if(fabs(first-second)<0.0001)
return true;
return false;
}
int main()
{
float x = (float) 1 / 3;
if(isEqual(x,0.3333))
printf("It is equal\n");
else
printf("It is not equal\n");
}
接下来是 "should" 秒。
我认为没有任何内容表明从 float 到 float (current_width = new_width
) 的赋值不能改变值,但如果存在这样的事情我会感到惊讶。除了直接复制之外,没有理由在相同类型的变量之间进行赋值。
如果传入的 new_width
和 new_height
保持它们的值直到它们改变,那么这个比较应该没有任何问题。但是如果在每次调用之前计算它们,它们可能会改变它们的值,这取决于计算是如何完成的。所以需要检查的不仅仅是这个功能
C 2011 标准表示计算可能使用比您分配给的格式更高的精度,但没有具体说明将一个变量分配给另一个变量。所以唯一的不精确应该在计算阶段。 "simple assignment" 部分 (6.5.16.1) 说:
In simple assignment (=), the value of the right operand is converted to the type of the assignment expression and replaces the value stored in the object designated by the left operand.
所以如果类型已经匹配,应该不需要转换。
因此,简单地说:如果您不在每次调用时重新计算传入值,则相等比较 应该 成立。但是真的存在您的帧缓冲区大小为浮点数而不是整数的情况吗?