我知道,这个问题似乎很奇怪。程序员有时会想太多。请继续阅读......
在C中我使用signed
和unsigned
整数。我喜欢这样一个事实:如果我执行诸如将有符号整数分配给无符号变量之类的操作,编译器会发出警告。如果我将带符号与无符号整数进行比较,我会得到警告。
我喜欢这些警告。他们帮助我保持我的代码正确。
为什么我们不能为花车提供同样的奢侈品?平方根绝对不会返回负数。还有其他地方负浮动值没有意义。无符号浮点数的完美候选者。
顺便说一句 - 我并不是真的热衷于通过从浮点数中移除符号位来获得的单一额外精度。我对他们现在的float
s非常满意。我只想将浮点数标记为无符号,并获得与整数相同的警告。
我不知道任何支持无符号浮点数的编程语言。
知道为什么他们不存在吗?
我知道x87 FPU没有处理无符号浮点数的指令。让我们使用带符号的浮点指令。误用(例如,低于零)可以被认为是未定义的行为,就像未定义有符号整数的溢出一样。
为什么C ++不支持无符号浮点数是因为CPU没有等效的机器代码操作来执行。因此支持它是非常低效的。
如果C ++确实支持它,那么你有时会使用unsigned float而没有意识到你的性能刚被杀死。如果C ++支持它,则需要检查每个浮点操作以查看它是否已签名。对于执行数百万次浮点运算的程序,这是不可接受的。
所以问题就是为什么硬件实施者不支持它。我认为答案是最初没有定义无符号浮点标准。由于语言喜欢向后兼容,即使添加了语言也无法使用它。要查看浮点规范,您应该查看IEEE standard 754 Floating-Point。
您可以通过创建一个封装浮点数或双精度的无符号浮点类并在尝试传入负数时抛出警告来解决没有无符号浮点类型的问题。这样效率较低,但是如果你没有强烈地使用它们,你可能不会关心那种轻微的性能损失。
我肯定看到有一个无符号浮点数的用处。但是C / C ++倾向于选择效率最高的安全性。
我怀疑这是因为C编译器所针对的底层处理器没有很好的方法来处理无符号浮点数。
IHMO是因为在硬件或软件中支持有符号和无符号浮点类型会非常麻烦
对于整数类型,我们可以在大多数情况下使用qzxswpoi使用2的补码的nice属性,因为the same logic unit for both signed and unsigned integer operations用于add,sub,non-widening mul和大多数按位运算。对于区分有符号和无符号版本的操作,我们仍然可以共享大部分逻辑。例如
INT_MIN
上很有用(如8080或8051)使用1的补码的系统也只需要对逻辑进行一点修改,因为它只是将进位位包裹到最低有效位。不确定标志幅度系统,但似乎他们systems that support only one type of comparison所以同样的事情适用
不幸的是,我们对于浮点类型并不那么奢侈。只需释放符号位,我们就可以使用无符号版本。但那我们应该用什么呢?
但是这两种选择都需要更大的加法器才能适应更广泛的价值范围。这增加了逻辑的复杂性,而加法器的顶部位在大多数时间都未使用。乘法,除法或其他复杂操作将需要更多的电路
在使用软件浮点的系统上,每个函数需要2个版本,这在内存非常昂贵的时候是不期望的,或者你必须找到一些“棘手”的方式来共享部分签名和未签名的函数
然而use 1's complement internally,所以我认为在C中的选择是由于缺乏硬件支持,因为我上面提到的原因
也就是说,存在几种专用的无符号浮点格式,主要用于图像处理,如floating-point hardware existed long before C was invented
C / C ++中有符号和无符号整数之间存在显着差异:
value >> shift
有符号值保持最高位不变(符号扩展),无符号值清除最高位。
没有无符号浮点数的原因是,如果没有负值,您会很快遇到各种问题。考虑一下:
float a = 2.0f, b = 10.0f, c;
c = a - b;
c有什么价值? -8。但是在没有负数的系统中这意味着什么。 FLOAT_MAX - 8也许吧?实际上,这不起作用FLOAT_MAX - 8由于精确效果而是FLOAT_MAX所以事情更加棘手。如果它是更复杂的表达式的一部分怎么办:
float a = 2.0f, b = 10.0f, c = 20.0f, d = 3.14159f, e;
e = (a - b) / d + c;
由于2的补码系统的性质,这不是整数的问题。
还要考虑标准的数学函数:sin,cos和tan只能用于输入值的一半,你找不到值<1的对数,你无法求解二次方程:x =( - b +/- root( bb - 4.ac))/ 2.a,依此类推。事实上,它可能不适用于任何复杂的函数,因为这些函数往往被实现为多项式近似,这将在某处使用负值。
所以,无符号浮点数是没用的。
但这并不意味着一个范围检查浮点值的类是没用的,您可能希望将值钳位到给定范围,例如RGB计算。
(另外,Perl 6允许你写
subset Nonnegative::Float of Float where { $_ >= 0 };
然后你可以像使用任何其他类型一样使用Nonnegative::Float
。)
对于无符号浮点运算没有硬件支持,因此C不提供它。 C主要设计为“便携式组装”,即尽可能靠近金属而不被绑定到特定平台。
[编辑]
C就像汇编:你看到的正是你得到的。隐含的“我会检查这个浮动对你来说是非负的”违背了它的设计理念。如果你真的想要它,你可以添加assert(x >= 0)
或类似的,但你必须明确地这样做。
我相信unsigned int的创建是因为需要比signed int提供的更大的值余量。
浮点数具有更大的余量,因此对于无符号浮点数从不存在“物理”需求。正如你在自己的问题中指出的那样,额外的1位精度是无可挽回的。
编辑:在阅读answer by Brian R. Bondy之后,我必须修改我的答案:他绝对是正确的,底层CPU没有无符号浮点运算。但是,我坚持认为这是基于我上述原因的设计决定;-)
我认为特雷布走在正确的轨道上。对于具有无符号对应类型的整数,这一点更为重要。那些是用于位移并用于位图的那些。一个标志位刚刚开始。例如,右移一个负值,结果值是在C ++中定义的实现。使用无符号整数或溢出这样的整数就可以完美地定义语义,因为在这种情况下没有这样的位。
因此,至少对于整数,需要单独的无符号类型比仅发出警告更强。对于花车,不需要考虑以上所有要点。因此,我认为没有真正需要对它们提供硬件支持,而C此时已经不支持它们了。
我想这取决于IEEE浮点规范只有签名并且大多数编程语言都使用它们。
wikipedia articla on ieee floating point numbers
编辑:另外,正如其他人所指出的,大多数硬件都不支持非负浮点数,因此正常类型的浮点数更有效,因为有硬件支持。
平方根绝对不会返回负数。还有其他地方负浮动值没有意义。无符号浮点数的完美候选者。
C99支持复数,以及sqrt的类型泛型形式,因此sqrt( 1.0 * I)
将为负数。
评论员强调了上面的一点点光泽,因为我指的是类型通用的sqrt
宏而不是函数,它将通过将复数截断到其实际组件来返回标量浮点值:
#include <complex.h>
#include <tgmath.h>
int main ()
{
complex double a = 1.0 + 1.0 * I;
double f = sqrt(a);
return 0;
}
它还包含一个脑屁,因为任何复数的sqrt的实部都是正数或零,sqrt(1.0 * I)是sqrt(0.5)+ sqrt(0.5)* I不是-1.0。
我认为主要原因是与无符号整数相比,无符号浮点数的用途非常有限。我不认为这是因为硬件不支持它。较旧的处理器根本没有浮点功能,它都是用软件模拟的。如果无符号浮点数很有用,它们将首先在软件中实现,硬件也会如此。
C中的无符号整数类型以遵循抽象代数环的规则的方式定义。例如,对于任何值X和Y,将XY添加到Y将产生X.无符号整数类型在所有情况下都保证遵守这些规则,这些规则不涉及到任何其他数字类型的转换[或不同大小的无符号类型] ,这种保证是此类型最重要的特征之一。在某些情况下,放弃表示负数的能力是值得的,以换取只有无符号类型才能提供的额外保证。浮点类型,无论是否有符号,都不能遵守代数环的所有规则[例如他们无法保证X + Y-Y等于X],而且IEEE甚至不允许他们遵守等价类的规则[通过要求某些值与自身不相等]。我不认为“无符号”浮点类型可以遵守普通浮点类型所不具备的任何公理,所以我不确定它会提供什么优势。