C / C ++中的最小双精度值


92

在C(++)程序中是否存在标准和/或可移植的方法来表示最小的负值(例如,使用负无穷大)?

float.h中的DBL_MIN是最小的数。


4
我会去-DBL_MAX,但我敢肯定有一些技术上的原因,事实并非如此:-)

4
@Neil,没有,它不像2个补码整数
fortran

我尚未在标准中看到任何要说的浮点类型范围必须在零附近对称的信息。但是limits.h和<limits>中的常量表明,C和C ++标准都希望它们会实现。
史蒂夫·杰索普

4
实际上,float.h中的DBL_MIN是最小的 归一化数。有些数字甚至更小。
fdermishin

1
@fortran:IEEE 754 FP使用符号位,并且当今肯定大多数FP硬件是IEEE754。但是C和C ++支持非IEEE 754 FP硬件,因此关于语言是否保证-DBL_MAX的问题尚待解决。必须等于最小可表示值。
j_random_hacker 2013年

Answers:


134

-DBL_MAX 在ANSI C中定义,它在float.h中定义。


这似乎是最标准和便携式
威尔

这是对我的-1的解释:谁或谁说-DBL_MAX由C或C ++语言保证是可表示的,更不用说最小的可表示值了?大多数FP硬件都符合IEEE 754标准,并且使用此表示形式,但这并不意味着-DBL_MAX可以保证在任何符合标准的C平台上工作。
j_random_hacker 2013年

@j_random_hacker:请参见下面的fortran回答。
JohnTortugo 2014年

3
@j_random_hacker这是一个很好的观点,但是C标准要求-DBL_MAX可以精确表示,因此,如果FP硬件不具备此功能,则实现只能解决该问题。请参阅5.2.4.2.2中C99的浮点类型<float.h> p2的特征(此后可能已移至其他地方)。

2
@j_random_hacker是的,但是p2指定e_min和e_max与符号位无关,因此DBL_MAX(1 − b ^ -p)b ^ e_max恰好是可表示的,最负的有限值恰好是-(1 − b ^ -p)b ^ e_max,并且由于恰好是-DBL_MAX,否定DBL_MAX也不会引入任何舍入误差。

70

浮点数(IEEE 754)是对称的,因此,如果可以表示最大值(DBL_MAXnumeric_limits<double>::max()),则只需在前面加上减号。

然后是很酷的方法:

double f;
(*((long long*)&f))= ~(1LL<<52);

6
+1对于指出浮点数的对称性:)
Andrew Hare

4
不使用IEEE 754浮点数的C / C ++实现又如何呢?
史蒂夫·杰索普

1
gcc的-ffast-math手册说:“设置-fno-math-errno,-funsafe-math优化,-ffinite-math仅,-fno-rounding-math,-fno-signaling-nans和-fcx-limited- range此选项不能由任何-O选项打开,因为它可能导致程序的输出不正确,而这些输出取决于准确执行IEEE或ISO规则/规范的数学函数,但是对于执行以下操作的程序,它可能会产生更快的代码不需要这些规格的保证。” 快速数学是一种常见设置,例如,英特尔ICC就是默认设置。总而言之,不知道这意味着什么,我:-)
威尔

4
这意味着实现不使用IEEE 754算法,但公平地说,这些选项仍然使用IEEE表示。您可能会发现使用非IEEE表示形式的某些仿真库,因为并非所有处理器都具有本机浮点格式(尽管它们可能会发布包含与制造商提供的仿真库相对应的格式的C ABI)。因此,并非所有编译器都可以使用一个。只是当您要求“标准和/或便携式”时是什么意思,原则上是便携式的,而实际上是便携式的。
史蒂夫·杰索普

3
您所说的对于IEEE 754是正确的,但是该标准不需要使用这种编码(如@SteveJessop所指出的,实践中的可移植性与原则上可移植性不同)。
Christophe

44

在C中使用

#include <float.h>

const double lowest_double = -DBL_MAX;

在C ++ pre-11中,使用

#include <limits>

const double lowest_double = -std::numeric_limits<double>::max();

在C ++ 11及更高版本中,使用

#include <limits>

constexpr double lowest_double = std::numeric_limits<double>::lowest();

min()C ++ 11之前的功能不可用吗?还是那个值不同于-max()cn.cppreference.com/w/cpp/types/numeric_limits
Alexis Wilke

5
@Alexis:如果查看链接页面上表的最低三行,您会看到,它min在幅度上的最小正值和在幅度上lowest的最大负值。是的,太可怕了。欢迎来到C ++标准库的辉煌世界:-P
rubenvb 2014年

对于C,它在中定义 float.hlimits.h是整数
CiprianTomoiagă15年

33

试试这个:

-1 * numeric_limits<double>::max()

参考: numeric_limits

该类专用于每种基本类型,其成员返回或设置为不同的值,这些值定义了类型在其编译的特定平台中具有的属性。


1
为什么不只是-numeric_limits<double>::max()呢?
k06a

4
@ k06a在这么长的表达式中用单个字符表示否定,字符串甚至说“ max”,肯定会迟早有人来。要么将其存储在描述性变量中,要么-1 * ...使它更加清晰。
Filip Haglund

20

您在寻找实际的无穷大还是最小的有限值?如果是前者,请使用

-numeric_limits<double>::infinity()

仅在以下情况下有效

numeric_limits<double>::has_infinity

否则,您应该使用

numeric_limits<double>::lowest()

这是C ++ 11中引入的。

如果lowest()没有,您可以退回到

-numeric_limits<double>::max()

这可能lowest()在原理上有所不同,但在实践中通常没有差异。


+1为有限值与无限值之差!但是标准不保证对称浮点编码。因此,-numeric_limits<double>::max()即使它在实践中起作用,理论上也不能完全移植。
Christophe

@克里斯托夫:[x]已修正
克里斯多夫

10

真正可移植的C ++解决方案

从C ++ 11开始,您可以使用 numeric_limits<double>::lowest()。根据标准,它完全返回您要查找的内容:

一个有限值x,使得在其中没有其他有限值y y < x
对于其中的所有专业意义重大is_bounded != false

在线演示


许多非便携式C ++答案在这里!

有很多答案 -std::numeric_limits<double>::max()

幸运的是,它们在大多数情况下都能正常工作。浮点编码方案将尾数分解成一个数字,然后将其分解为指数,并且大多数(例如流行的IEEE-754)使用一个不属于尾数的独特符号位。只需翻转符号,就可以将最大的正数转换为最小的负数:

在此处输入图片说明

为什么这些不便携?

该标准不强加任何浮点标准。

我同意我的观点有点理论上的观点,但是假设某些偏心的编译器制造商将使用革命性的编码方案,尾数以a的一些变体进行编码。 二进制补码的体。二进制补码不对称。例如,对于带符号的8位字符,最大正数为127,但是最小负数为-128。因此,我们可以想象一些浮点编码显示出类似的不对称行为。

我不知道类似的任何编码方案,但关键是该标准不能保证符号翻转会产生预期的结果。因此,这个流行的答案(对不起,伙计们!)不能视为完全可移植的标准解决方案!/ *至少在您没有断言numeric_limits<double>::is_iec559是真的的情况下* /



1

最初的问题涉及无穷大。所以,为什么不使用

#define Infinity  ((double)(42 / 0.0))

根据IEEE的定义?您当然可以取消它。


好主意 !而且有效。但只有当numeric_limits<double>::has_infinity && ! numeric_limits<double>::traps
Christophe

1

在C(++)程序中是否存在标准和/或可移植的方法来表示最小的负值(例如,使用负无穷大)?

C方式。

许多实现都支持+/-无穷大,因此最大的负值double-INFINITY

#include <math.h>
double most_negative = -INFINITY;

是否有标准和/或便携式的方式...?

现在我们还需要考虑其他情况:

  • 没有无限

简单地说-DBL_MAX

  • 只有一个无符号的无穷大。

我希望在这种情况下,OP会更喜欢-DBL_MAX

  • 异常值的幅度大于DBL_MAX

这是一个不寻常的情况,可能超出OP的关注范围。当double将其编码为一对浮点以实现所需的范围/进动时(请参见double-double),存在一个最大法线 double,也许还有一个更大的非法线。我看过辩论是否DBL_MAX应该指最大的常态和两者中的最大者。

幸运的是,这种配对方法通常包括-infinity,因此,最大负值仍然存在-INFINITY


为了实现更高的可移植性,代码可以顺其自然

// HUGE_VAL is designed to be infinity or DBL_MAX (when infinites are not implemented)
// .. yet is problematic with unsigned infinity.
double most_negative1 = -HUGE_VAL;  

// Fairly portable, unless system does not understand "INF"
double most_negative2 = strtod("-INF", (char **) NULL);

// Pragmatic
double most_negative3 = strtod("-1.0e999999999", (char **) NULL);

// Somewhat time-consuming
double most_negative4 = pow(-DBL_MAX, 0xFFFF /* odd value */);

// My suggestion
double most_negative5 = (-DBL_MAX)*DBL_MAX;

-1

如果您没有启用float异常(不应该恕我直言),则可以简单地说:

double neg_inf = -1/0.0;

这产生负无穷大。如果需要浮点数,则可以强制转换结果

float neg_inf = (float)-1/0.0;

或使用单精度算术

float neg_inf = -1.0f/0.0f;

结果始终是相同的,单精度和双精度都有一个负无穷大的表示形式,并且它们可以按照您的期望相互转换。


你为什么会做这个,而不是只写-INFINITY
MM

同样,无穷大可能存在也可能不存在,如果存在,那么正负之间可能无法区分(在标准C中)。
MM

在许多编译器和/或体系结构中,您的C / C ++代码将减慢许多您传播无穷大和NaN值的速度。
markgalassi

@markgalassi请仔细看看:您会注意到它neg_inf已初始化为一个常量值。编译器将负责计算inf值。而且当您将其用作计算最大值的空值时,第一次迭代通常会使用较大的值覆盖它。即性能几乎不是问题。OP专门询问“例如使用负无穷大”,-inf这确实是对此的唯一正确答案。您否决了正确且有用的答案。
cmaster-恢复莫妮卡
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.