免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: pmerofc
打印 上一主题 下一主题

费解的难题:编译器错了吗? [复制链接]

论坛徽章:
95
程序设计版块每日发帖之星
日期:2015-09-05 06:20:00程序设计版块每日发帖之星
日期:2015-09-17 06:20:00程序设计版块每日发帖之星
日期:2015-09-18 06:20:002015亚冠之阿尔艾因
日期:2015-09-18 10:35:08月度论坛发贴之星
日期:2015-09-30 22:25:002015亚冠之阿尔沙巴布
日期:2015-10-03 08:57:39程序设计版块每日发帖之星
日期:2015-10-05 06:20:00每日论坛发贴之星
日期:2015-10-05 06:20:002015年亚冠纪念徽章
日期:2015-10-06 10:06:482015亚冠之塔什干棉农
日期:2015-10-19 19:43:35程序设计版块每日发帖之星
日期:2015-10-21 06:20:00每日论坛发贴之星
日期:2015-09-14 06:20:00
21 [报告]
发表于 2012-03-26 20:43 |只看该作者
pmerofc 发表于 2012-03-26 20:33
我觉得实际上代码中的 f * f 与 1.234567f * 1.234567f 其实是
(double)(f * f) 与 (double)(1.234567 ...


你看看 C 中的隱式類型轉換和 printf 中的類型提昇是怎麼規定的吧。不過你代碼的主要問題不在這,而是有效數字用得不對。

论坛徽章:
2
程序设计版块每日发帖之星
日期:2015-06-17 22:20:00每日论坛发贴之星
日期:2015-06-17 22:20:00
22 [报告]
发表于 2012-03-26 21:02 |只看该作者
提示: 作者被禁止或删除 内容自动屏蔽

论坛徽章:
95
程序设计版块每日发帖之星
日期:2015-09-05 06:20:00程序设计版块每日发帖之星
日期:2015-09-17 06:20:00程序设计版块每日发帖之星
日期:2015-09-18 06:20:002015亚冠之阿尔艾因
日期:2015-09-18 10:35:08月度论坛发贴之星
日期:2015-09-30 22:25:002015亚冠之阿尔沙巴布
日期:2015-10-03 08:57:39程序设计版块每日发帖之星
日期:2015-10-05 06:20:00每日论坛发贴之星
日期:2015-10-05 06:20:002015年亚冠纪念徽章
日期:2015-10-06 10:06:482015亚冠之塔什干棉农
日期:2015-10-19 19:43:35程序设计版块每日发帖之星
日期:2015-10-21 06:20:00每日论坛发贴之星
日期:2015-09-14 06:20:00
23 [报告]
发表于 2012-03-26 21:29 |只看该作者
pmerofc 发表于 2012-03-26 21:02
简单地说
就是
d=f*f  不是按照 d = (double)(f*f)来求值 ,而是按照d = (double)f*(double)f 来求值的 ...


你在哪看出這個的?

论坛徽章:
2
程序设计版块每日发帖之星
日期:2015-06-17 22:20:00每日论坛发贴之星
日期:2015-06-17 22:20:00
24 [报告]
发表于 2012-03-26 21:41 |只看该作者
提示: 作者被禁止或删除 内容自动屏蔽

论坛徽章:
0
25 [报告]
发表于 2012-03-26 22:43 |只看该作者
pmerofc 发表于 2012-03-26 21:02
简单地说
就是
d=f*f  不是按照 d = (double)(f*f)来求值 ,而是按照d = (double)f*(double)f 来求值的 ...


C标准规定就是d = (double)(f *f),只不过在x86上变样了而已,x86把所有float在第一时间转换成了double,因此d = f * f在 x86 上就变成了d = double(f) *double(f)。所以我之前也说了,软件实现看起来更贴合标准,但是标准也得屈服于平台实现。

http://msdn.microsoft.com/zh-cn/library/aa289157(v=vs.71).aspx#EKAA

fp:precise 模式下特定于体系结构的舍入:x86:
按照具有 16 位指数所提供的扩展范围的、默认的 53 位精度计算中 间表达式。当这些 53:16 值被“倒”入内存时(这在函数调用期间可能发生),扩展指数范围将被缩 小到 11 位。也就是说,倒入内存的值被转换为标准的双精度格式,只具有 11 位指数。

通过使用 _controlfp 改变浮点控制字或者通过启用 FPU 环境访问,用户可以为中间结果 的舍入切换到扩展的 64 位精度(请参阅 fpenv_access 杂注)。然而,当扩展精度寄存器值被倒入内存时,中间结果仍 将舍入到双精度。

这一特定语义随时可能更改。

论坛徽章:
2
程序设计版块每日发帖之星
日期:2015-06-17 22:20:00每日论坛发贴之星
日期:2015-06-17 22:20:00
26 [报告]
发表于 2012-03-26 22:46 |只看该作者
提示: 作者被禁止或删除 内容自动屏蔽

论坛徽章:
0
27 [报告]
发表于 2012-03-26 22:56 |只看该作者
再给你看看 Intel 的说法:

前面介绍了x87 FPU有8个80位扩展双精度的寄存器用于数据计算。支持的数据编码格式,除了整形,浮点有三种:单精度float,双精度double,和扩展双精度 long double,接下来描述这三种的用途
As a general rule, values should be stored in memory in double-precision format. This format provides sufficient range and precision to return correct results with a minimum of programmer attention.

The single-precision format is useful for debugging algorithms, because rounding problems will manifest themselves more quickly in this format.

The double extended-precision format is normally reserved for holding intermediate results in the x87 FPU registers and constants. Its extra length is designed to shield final results from the effects of rounding and overflow/underflow in intermediate calculations. However, when an application requires the maximum range and precision of the x87 FPU (for data storage, computations, and results), values can be stored in memory in double extended-precision format.


所以你想让x87 FPU进行一次单精度舍入的乘法运算是不可能的,x86平台上只有软件模拟才能做到。

论坛徽章:
2
程序设计版块每日发帖之星
日期:2015-06-17 22:20:00每日论坛发贴之星
日期:2015-06-17 22:20:00
28 [报告]
发表于 2012-03-26 23:21 |只看该作者
提示: 作者被禁止或删除 内容自动屏蔽

论坛徽章:
0
29 [报告]
发表于 2012-03-26 23:40 |只看该作者
本帖最后由 sonicling 于 2012-03-26 23:41 编辑

回复 28# pmerofc


    那你就骂C++编译器吧,因为C++标准明确规定了每个operator的操作数类型和表达式类型,并且明确说了左右操作数类型的提升关系,而C标准语焉不详,只说 * 的操作数必须是算术类型,结果必须是算术类型,结果的值是两边的乘积,没有说类型该如何处理。

C99:Semantics
3 The usual arithmetic conversions are performed on the operands.
4 The result of the binary * operator is the product of the operands.


C标准只说在操作数上进行算术转换,没说转换为什么。(所以float先转换为double再计算也是可以的。)

C++2003:
@built-in operators:
12 For every pair of promoted arithmetic types L and R, there exist candidate operator functions of the form
    LR operator*(L, R);

@multiplication-expression:
2 The operands of * and / shall have arithmetic or enumeration type; the operands of % shall have integral or enumeration type. The usual arithmetic conversions are performed on the operands and determine the type of the result.


C++ 明确了只能在左右类型间进行提升转换,并由此确定表达式的类型。(左右两边都是float的情况下,不可能提升为double)

论坛徽章:
2
程序设计版块每日发帖之星
日期:2015-06-17 22:20:00每日论坛发贴之星
日期:2015-06-17 22:20:00
30 [报告]
发表于 2012-03-27 08:18 |只看该作者
提示: 作者被禁止或删除 内容自动屏蔽
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP