浮点和宽寄存器 [英] Floating Point and Wide Registers

查看:75
本文介绍了浮点和宽寄存器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

9899:1999 5.1.2.3示例4读取:

示例4使用宽寄存器的实现必须小心

以遵守适当的语义。值与它们是否在寄存器或内存中表示无关。例如,不允许对寄存器进行隐式

溢出来改变该值。此外,需要一个

显式存储和加载来舍入到

存储类型的精度。特别是,演员和作业需要

执行他们指定的转换。对于片段


双d1,d2;

浮动f;

d1 = f =表达式;

d2 =(浮点)表达式;


分配给d1和d2的值需要转换为

float。"


以下程序的输出是:


d3!= d1 * d2

d3!=(double) (d1 * d2)

fdim == 0


我预计输出


d3!= d1 * d2

d3 ==(双)(d1 * d2)

fdim == 0


这是程序:


#include< math.h>

#include< stdio.h>


int main (无效){

双d1,d2,d3;

d1 = 0.1;

d2 = 10.0;

d3 = d1 * d2;


/ *第一部分* /

if(d3 == d1 * d2)

puts(" d3 == d1 * d2");

else

puts(" d3!= d1 * d2");

/ *第二部分* /

如果(d3 ==(double)(d1 * d2))

puts(" d3 ==(double)(d1 * d2)");

else

put(" d3!=(double)(d1 * d2)");


/ *第三部分* /

if(fdim(d3,d1 * d2)== 0)

puts(" fdim == 0");

else

put(" fdim!= 0");


返回0;

}


它是用gcc编译的-Wall -W -std = c99 -pedantic


我理解浮点运算的缺陷我理解

是怎么回事这里。在我的机器上(x86)浮点运算

在80位寄存器中执行,双精度是64位。在第一个

示例中,编译器正在计算80位寄存器中的乘法结果,并将结果与​​双精度值进行比较

精度。结果并不出乎意料,因为d3在存储到64位对象时会丢失一些精度

但是

乘法的结果没有经历这种损失。我没有问题

这是符合AFAICT标准的。

对于我来说意想不到的部分是结果的第二部分<乘法的
显式地转换为double,根据我对上面引用的标准经文的解释,要求

结果是如果执行,则在测试之前转换为较窄类型的双重
相等。这似乎没有发生。如果我使用

gcc选项-ffloat-store,结果是按预期的那样,但是在符合标准的模式下不应该要求这个


程序最后一部分的结果显示,当结果为d1 * d2时,结果为b1 * d2。实际上转换为双倍,它比较等于

d3。


所以我的问题是:我的解释是否正确并且是

保证第二部分?如果没有,我哪里出错了?


Robert Gamble

9899:1999 5.1.2.3 Example 4 reads:
"EXAMPLE 4 Implementations employing wide registers have to take care
to honor appropriate semantics. Values are independent of whether they
are represented in a register or in memory. For example, an implicit
spilling of a register is not permitted to alter the value. Also, an
explicit store and load is required to round to the precision of the
storage type. In particular, casts and assignments are required to
perform their specified conversion. For the fragment

double d1, d2;
float f;
d1 = f = expression;
d2 = (float) expression;

the values assigned to d1 and d2 are required to have been converted to
float."

The output of the following program is:

d3 != d1 * d2
d3 != (double) (d1 * d2)
fdim == 0

I expected an output of

d3 != d1 * d2
d3 == (double) (d1 * d2)
fdim == 0

Here is the program:

#include <math.h>
#include <stdio.h>

int main (void) {
double d1, d2, d3;
d1 = 0.1;
d2 = 10.0;
d3 = d1 * d2;

/* First part */
if (d3 == d1 * d2)
puts("d3 == d1 * d2");
else
puts("d3 != d1 * d2");

/* Second part */
if (d3 == (double) (d1 * d2))
puts("d3 == (double) (d1 * d2)");
else
puts("d3 != (double) (d1 * d2)");

/* Third part */
if (fdim(d3, d1 * d2) == 0)
puts("fdim == 0");
else
puts("fdim != 0");

return 0;
}

It was compiled with gcc using -Wall -W -std=c99 -pedantic

I understand the pitfalls of floating point arithmetic and I understand
what is going on here. On my machine (x86) floating point arithmetic
is performed in 80-bit registers and doubles are 64-bits. In the first
example the compiler is computing the result of the multiplication in
an 80-bit register and comparing the result to the double with less
precision. The result is not unexpected because d3 lost some precision
when it was stored into a 64-bit object but the result of the
multiplication did not undergo this loss. I don''t have a problem with
this, it is AFAICT Standard conforming.
The part that is unexpected, to me, is the second part where the result
of the multiplication is explicitly cast to double which, according to
my interpretation of the above-quoted Standard verse, requires that the
result is converted to the narrower type of double before the test for
equality if performed. This does not appear to be happening. If I use
the gcc option -ffloat-store the result is as expected but this
shouldn''t be required in a Standard-conforming mode.
The result of the last part of the program shows that when the results
of "d1 * d2" is actually converted to a double, it compares equal to
d3.

So my question is: Is my interpretation correct and are the results of
the second two parts guaranteed? If not, where did I go wrong?

Robert Gamble

推荐答案

Robert Gamble schrieb:

< snip:强制转换为double应该强制键入double

和适当的截断但不是>
Robert Gamble schrieb:
<snip: Cast to double should force the value to type double
and appropriate truncation but does not>

它是用gcc编译的-Wall -W -std = c99 -pedantic


我理解漂浮的陷阱点算术,我理解

这里发生了什么。在我的机器上(x86)浮点运算

在80位寄存器中执行,双精度是64位。在第一个

示例中,编译器正在计算80位寄存器中的乘法结果,并将结果与​​双精度值进行比较

精度。结果并不出乎意料,因为d3在存储到64位对象时会丢失一些精度

但是

乘法的结果没有经历这种损失。我没有问题

这是符合AFAICT标准的。

对于我来说意想不到的部分是结果的第二部分<乘法的
显式地转换为double,根据我对上面引用的标准经文的解释,要求

结果是如果执行,则在测试之前转换为较窄类型的双重
相等。这似乎没有发生。如果我使用

gcc选项-ffloat-store,结果是按预期的那样,但是在符合标准的模式下不应该要求这个


程序最后一部分的结果显示,当结果为d1 * d2时,结果为b1 * d2。实际上转换为双倍,它比较等于

d3。


所以我的问题是:我的解释是否正确并且是

保证第二部分?如果没有,我哪里出错了?
It was compiled with gcc using -Wall -W -std=c99 -pedantic

I understand the pitfalls of floating point arithmetic and I understand
what is going on here. On my machine (x86) floating point arithmetic
is performed in 80-bit registers and doubles are 64-bits. In the first
example the compiler is computing the result of the multiplication in
an 80-bit register and comparing the result to the double with less
precision. The result is not unexpected because d3 lost some precision
when it was stored into a 64-bit object but the result of the
multiplication did not undergo this loss. I don''t have a problem with
this, it is AFAICT Standard conforming.
The part that is unexpected, to me, is the second part where the result
of the multiplication is explicitly cast to double which, according to
my interpretation of the above-quoted Standard verse, requires that the
result is converted to the narrower type of double before the test for
equality if performed. This does not appear to be happening. If I use
the gcc option -ffloat-store the result is as expected but this
shouldn''t be required in a Standard-conforming mode.
The result of the last part of the program shows that when the results
of "d1 * d2" is actually converted to a double, it compares equal to
d3.

So my question is: Is my interpretation correct and are the results of
the second two parts guaranteed? If not, where did I go wrong?



您的解释是正确的;事实上,即使是-ffloat-store也不足以迫使gcc遵守行为;请参阅

示例,我自己也提出类似的问题,
http://groups.google.de/group/comp.l...d30d2f1380f0f1


这是一个真正恼人的gcc功能。

干杯

Michael

-

电子邮件:我的是一个/ at / gmx / dot / de address。

Your interpretation is correct; in fact, even -ffloat-store is not
always enough to force gcc to conforming behaviour; see, for
example, a similar question by myself,
http://groups.google.de/group/comp.l...d30d2f1380f0f1

This is a truly annoying feature of gcc.
Cheers
Michael
--
E-Mail: Mine is an /at/ gmx /dot/ de address.


Robert Gamble写道:
Robert Gamble wrote:

9899:1999 5.1。 2.3示例4读取:

示例4使用宽寄存器的实现必须小心

以遵守适当的语义。值与它们是否在寄存器或内存中表示无关。例如,不允许对寄存器进行隐式

溢出来改变该值。此外,需要一个

显式存储和加载来舍入到

存储类型的精度。特别是,演员和作业需要

执行他们指定的转换。对于片段


双d1,d2;

浮动f;

d1 = f =表达式;

d2 =(浮点)表达式;


分配给d1和d2的值需要转换为

float。"


以下程序的输出是:


d3!= d1 * d2

d3!=(double) (d1 * d2)

fdim == 0


我预计输出


d3!= d1 * d2

d3 ==(双)(d1 * d2)

fdim == 0


这是程序:


#include< math.h>

#include< stdio.h>


int main (无效){

双d1,d2,d3;

d1 = 0.1;

d2 = 10.0;

d3 = d1 * d2;


/ *第一部分* /

if(d3 == d1 * d2)

puts(" d3 == d1 * d2");

else

puts(" d3!= d1 * d2");

/ *第二部分* /
if(d3 ==(double)(d1 * d2))

puts(" d3 ==(double)(d1 * d2)"); br />
else

puts(" d3!=(double)(d1 * d2)");


/ *第三部分* /

if(fdim(d3,d1 * d2)== 0)

puts(" fdim == 0");

else

puts(" fdim!= 0");


返回0;

}


它是用gcc编译的-Wall -W -std = c99 -pedantic


我理解浮点运算的缺陷我明白了

这里发生了什么。在我的机器上(x86)浮点运算

在80位寄存器中执行,双精度是64位。在第一个

示例中,编译器正在计算80位寄存器中的乘法结果,并将结果与​​双精度值进行比较

精度。结果并不出乎意料,因为d3在存储到64位对象时会丢失一些精度

但是

乘法的结果没有经历这种损失。我没有问题

这是符合AFAICT标准的。

对于我来说意想不到的部分是结果的第二部分<乘法的
显式地转换为double,根据我对上面引用的标准经文的解释,要求

结果是如果执行,则在测试之前转换为较窄类型的双重
相等。这似乎没有发生。如果我使用

gcc选项-ffloat-store,结果是按预期的那样,但是在符合标准的模式下不应该要求这个


程序最后一部分的结果显示,当结果为d1 * d2时,结果为b1 * d2。实际上转换为双倍,它比较等于

d3。


所以我的问题是:我的解释是否正确并且是

保证第二部分?如果没有,我哪里出错了?


Robert Gamble
9899:1999 5.1.2.3 Example 4 reads:
"EXAMPLE 4 Implementations employing wide registers have to take care
to honor appropriate semantics. Values are independent of whether they
are represented in a register or in memory. For example, an implicit
spilling of a register is not permitted to alter the value. Also, an
explicit store and load is required to round to the precision of the
storage type. In particular, casts and assignments are required to
perform their specified conversion. For the fragment

double d1, d2;
float f;
d1 = f = expression;
d2 = (float) expression;

the values assigned to d1 and d2 are required to have been converted to
float."

The output of the following program is:

d3 != d1 * d2
d3 != (double) (d1 * d2)
fdim == 0

I expected an output of

d3 != d1 * d2
d3 == (double) (d1 * d2)
fdim == 0

Here is the program:

#include <math.h>
#include <stdio.h>

int main (void) {
double d1, d2, d3;
d1 = 0.1;
d2 = 10.0;
d3 = d1 * d2;

/* First part */
if (d3 == d1 * d2)
puts("d3 == d1 * d2");
else
puts("d3 != d1 * d2");

/* Second part */
if (d3 == (double) (d1 * d2))
puts("d3 == (double) (d1 * d2)");
else
puts("d3 != (double) (d1 * d2)");

/* Third part */
if (fdim(d3, d1 * d2) == 0)
puts("fdim == 0");
else
puts("fdim != 0");

return 0;
}

It was compiled with gcc using -Wall -W -std=c99 -pedantic

I understand the pitfalls of floating point arithmetic and I understand
what is going on here. On my machine (x86) floating point arithmetic
is performed in 80-bit registers and doubles are 64-bits. In the first
example the compiler is computing the result of the multiplication in
an 80-bit register and comparing the result to the double with less
precision. The result is not unexpected because d3 lost some precision
when it was stored into a 64-bit object but the result of the
multiplication did not undergo this loss. I don''t have a problem with
this, it is AFAICT Standard conforming.
The part that is unexpected, to me, is the second part where the result
of the multiplication is explicitly cast to double which, according to
my interpretation of the above-quoted Standard verse, requires that the
result is converted to the narrower type of double before the test for
equality if performed. This does not appear to be happening. If I use
the gcc option -ffloat-store the result is as expected but this
shouldn''t be required in a Standard-conforming mode.
The result of the last part of the program shows that when the results
of "d1 * d2" is actually converted to a double, it compares equal to
d3.

So my question is: Is my interpretation correct and are the results of
the second two parts guaranteed? If not, where did I go wrong?

Robert Gamble



lcc-win32编译器的输出是:


d3!= d1 * d2 // OK

d3!=(双)(d1 * d2)//这是问题

fdim == 0 // OK

为什么?


因为d1 * d2的结果已经是double类型,而且

编译器(可能像gcc)认为任何类型转换为同一类型

是NOP(无操作)。


如果你写的话:

int a,b;


b =(int)((int)a +(int)b);


将生成相同的代码,就像你写的一样:


b = a + b;


你这是正确的不是编译器应该做的,而且它是

a bug,一个转换为double应该做一个演员。


如果你把比较更改为


if(d3 ==(double)(float)(d1 * d2))


那么结果是

d3 ==(double)(d1 * d2);


因为lcc-win32强制演员因为浮动!=双。

The output for the lcc-win32 compiler is:

d3 != d1 * d2 // OK
d3 != (double) (d1 * d2) // This is the problem
fdim == 0 // OK
Why?

Because the result of d1 * d2 is already of type double, and the
compiler (probably like gcc) thinks that any cast to the same type
is a NOP (no operation).

If you write:
int a,b;

b = (int)((int)a + (int)b);

the same code will be generated as if you had written:

b = a+b;

You are correct that this is not what the compiler should do, and it is
a bug, a cast to double should do a cast.

If you change the comparison to

if (d3 == (double) (float)(d1 * d2))

THEN the result is

d3 == (double) (d1 * d2);

because lcc-win32 forces the cast since float != double.


我发现最好不要期望漂浮 - 点平等或

不平等。


很多时候,无论是谁写了这样的测试都没有在所有的
$ b $上用fp算法可能发生的小小的抖动。而且很少有人实际上寻求平等,更有可能会满足于在一些小的三角洲内的


I''ve found it best to NEVER expect floating-point equality or
non-equality.

A goodly bit of the time whoever writes such a test isnt up on all the
little jiggles that can happen with fp arithmetic. And one is rarely
actually looking for equality, more likely would be satisfied with
being within some small delta.


这篇关于浮点和宽寄存器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆