67 c++ int promotions types floating-point-conversion
说我有以下内容:
int i = 23;
float f = 3.14;
if (i == f) // do something
Run Code Online (Sandbox Code Playgroud)
i将被提升为a float并将两个float数字进行比较,但是可以float代表所有int值吗?为什么不提倡既int和float一个double?
Win*_*ute 68
当int被提升到unsigned在积分促销,负值也会丢失(这会导致这样的乐趣,0u < -1是真的).
与C中的大多数机制(在C++中继承)一样,应该通过硬件操作来理解通常的算术转换.C的制造者非常熟悉他们所使用的机器的汇编语言,他们编写C以便在编写将在程序集中编写的内容(例如UNIX)之前立即对自己和类似自己的人有所了解.核心).
现在,处理器通常不具有混合类型指令(将float添加到double,将int与float等进行比较),因为这将极大地浪费晶圆上的不动产 - 您必须实现你希望支持不同类型的操作码数量多很多倍.你只有"add int to int","compare float to float","multipigned unsigned with unsigned"等指令,首先需要通常的算术转换 - 它们是两种类型到指令的映射与他们一起使用最有意义的家庭.
从曾经用于编写低级机器代码的人的角度来看,如果你有混合类型,那么在一般情况下你最有可能考虑的汇编程序指令是那些需要转换次数最少的指令.对于浮点而言尤其如此,其中转换在运行时是昂贵的,特别是在20世纪70年代早期,当C开发,计算机速度慢以及浮点计算在软件中完成时.这表明在通常的算术转换-只有一个操作数是不断转换(与唯一例外long/ unsigned int,其中,long可转换为unsigned long,它不需要任何在异常适用于可在大多数机器做也许不会对任何. ).
因此,通常的算术转换被编写为执行汇编编码器大多数时间会执行的操作:您有两种不适合的类型,将它们转换为另一种类型.这是你的汇编代码做什么,除非你有特别的理由不这样做,和谁是用来编写汇编程序代码,人们也有一个具体的理由,迫使不同的转换,明确请求转换是很自然的.毕竟,你可以简单地写
if((double) i < (double) f)
Run Code Online (Sandbox Code Playgroud)
顺便说一下,在这种情况下,有趣的unsigned是,在层次结构中,层次比在层次结构中更高int,因此int与unsigned将比较将以无符号比较结束(因此0u < -1从头开始).我怀疑这是一个指标,在过去,人们认为它unsigned不是一个限制,int而是作为其价值范围的延伸:我们现在不需要这个标志,所以让我们使用额外的比特来获得更大的价值范围.如果你有理由期望int会溢出,你会使用它- 在16位int的世界中更大的担忧.
doc*_*doc 13
甚至double可能无法表示所有int值,具体取决于int包含的位数.
为什么不将int和float都提升为double?
可能是因为它更昂贵的两种类型的转换double不是使用一个操作数,这已经是一个float作为float.它还将为与算术运算符规则不兼容的比较运算符引入特殊规则.
也不能保证浮点类型将如何表示,因此假设转换int为double(或甚至long double)进行比较将解决任何问题将是一个盲目的镜头.
Gio*_*tta 10
类型提升规则旨在简单并以可预测的方式工作.C/C++中的类型自然地按它们可以表示的值的范围 "排序" .请参阅此了解详情.虽然浮点类型不能表示由整数类型表示的所有整数,因为它们不能表示相同数量的有效数字,但它们可能能够表示更宽的范围.
为了具有可预测的行为,当需要类型提升时,数字类型总是被转换为具有较大范围的类型,以避免较小范围中的溢出.想象一下:
int i = 23464364; // more digits than float can represent!
float f = 123.4212E36f; // larger range than int can represent!
if (i == f) { /* do something */ }
Run Code Online (Sandbox Code Playgroud)
如果转换是针对整数类型进行的,则浮点数f在转换为int时肯定会溢出,从而导致未定义的行为.另一方面,转换i为f仅导致精度损失,这是无关紧要的,因为f具有相同的精度,因此仍然可能比较成功.此时程序员可以根据应用程序要求来解释比较结果.
最后,除了双精度浮点数遇到表示整数的相同问题(有限数量的有效数字)这一事实外,在两种类型上使用促销将导致具有更高的精度表示i,同时f注定具有原始精度,因此,如果i数字比f开头更有效,那么比较将不会成功.现在这也是未定义的行为:对于某些情侣(i,f)而不是其他情侣,比较可能会成功.
可以
float代表所有int价值吗?
对于一个典型的现代体系,其中两个int和float被存储在32位,无.有些东西必须给予.32位的整数不会将1对1映射到包含分数的相同大小的集合.
在
i将被提升到一个float和两个float数字进行比较...
不必要.你真的不知道什么是精确度.C++14§5/ 12:
浮动操作数的值和浮动表达式的结果可以以比该类型所需的精度和范围更高的精度和范围来表示; 因此不改变类型.
虽然i促销后具有名义类型float,但可以使用double硬件来表示该值.C++不保证浮点精度丢失或溢出.(这在C++ 14中并不新鲜;它从古代开始就从C继承.)
为什么不提倡既
int和float一个double?
如果你想要在任何地方都达到最佳精度,double那么请改用它,你永远不会看到它float.或者long double,但这可能会运行得更慢.考虑到一台机器可能提供多种替代精度,这些规则对于大多数有限精度类型的用例而言是相对合理的.
大多数时候,快速和松散都足够好,所以机器可以自由地做任何最简单的事情.这可能意味着圆形,单精度比较,或双精度和无圆角.
但是,这些规则最终是妥协,有时它们会失败.要在C++(或C)中精确指定算术,有助于明确转换和促销.许多超可靠软件的样式指南禁止完全使用隐式转换,大多数编译器提供警告以帮助您清除它们.
要了解这些妥协是如何产生的,您可以仔细阅读C理论文档.(最新版本涵盖C99.)从PDP-11或K&R时代起,它不仅是毫无意义的包袱.
小智 6
令人着迷的是,这里的一些答案来自C语言的起源,明确地将K&R和历史包袱命名为将int与浮点数组合转换为浮点数的原因.
这指责错误的政党.在K&R C中,没有浮动计算这样的东西. 所有浮点运算都以双精度完成.出于这个原因,一个整数(或其他任何东西)从未隐式转换为float,而只是一个double.float也不能是函数参数的类型:如果你真的真的想要避免转换为double,你必须将指针传递给float.出于这个原因,功能
int x(float a)
{ ... }
Run Code Online (Sandbox Code Playgroud)
和
int y(a)
float a;
{ ... }
Run Code Online (Sandbox Code Playgroud)
有不同的调用约定.第一个得到一个浮点参数,第二个(现在不再允许作为语法)得到一个双参数.
单精度浮点运算和函数参数仅在ANSI C中引入.Kernighan/Ritchie是无辜的.
现在使用新的单浮点表达式(单浮点数以前只是一种存储格式),还必须有新的类型转换.无论ANSI C团队在这里挑选什么(我会为更好的选择而感到茫然)并不是K&R的错.
Q1:float可以表示所有int值吗?
IEE754可以将所有整数完全表示为浮点数,最多约为2 23,如本答案中所述.
Q2:为什么不将int和float都提升为double?
这些转换的标准中的规则是对K&R中的规则的略微修改:修改适应添加的类型和保留值规则.添加显式许可证以在"更广泛"的类型中执行计算,而不是绝对必要的,因为这有时会产生更小更快的代码,更不用说更频繁的正确答案了.只要获得相同的最终结果,也可以通过as if规则以"较窄"类型执行计算.可以始终使用显式转换来获得所需类型的值.
在更广泛的类型执行计算意味着给定的float f1;和float f2;,f1 + f2可能在计算double精度.这也意味着,鉴于int i;并且float f;,i == f可能在计算double精度.但它不需要以i == f双精度计算,正如hvd在评论中所述.
C标准也这样说.这些被称为通常的算术转换.以下描述直接取自ANSI C标准.
...如果任一操作数的类型为float,则另一个操作数将转换为float类型.
下面是解释这个问题的另一种方法:隐式执行通常的算术转换以将它们的值转换为通用类型.编译器首先执行整数提升,如果操作数仍然具有不同的类型,则它们将转换为在以下层次结构中显示最高的类型:

来源.
| 归档时间: |
|
| 查看次数: |
8136 次 |
| 最近记录: |