可以存储在IEEE 754双类型中而不损失精度的最大“无浮动”整数是多少?
换句话说,at会返回以下代码片段:
UInt64 i = 0;
Double d = 0;
while (i == d)
{
i += 1;
d += 1;
}
Console.WriteLine("Largest Integer: {0}", i-1);
可以存储在IEEE 754双类型中而不损失精度的最大“无浮动”整数是多少?
换句话说,at会返回以下代码片段:
UInt64 i = 0;
Double d = 0;
while (i == d)
{
i += 1;
d += 1;
}
Console.WriteLine("Largest Integer: {0}", i-1);
当前回答
的确,对于64位的IEEE754双精度,所有到9007199254740992 == 2^53的整数都可以精确表示。
然而,值得一提的是,所有超出4503599627370496 == 2^52的可表示数字都是整数。 超过2^52,测试它们是否是整数就没有意义了,因为它们都隐式舍入到附近一个可表示的值。
在2^51到2^52的范围内,唯一的非整数值是以“”结尾的中点。5”,这意味着计算后的任何整数测试都必须产生至少50%的错误答案。
在2^51以下也有"25"和"。75英寸,所以比较一个数字和它的四舍五入的对应数字,以确定它是否可能是整数开始是有意义的。
TLDR:如果您想测试计算结果是否可能是整数,请避免大于2251799813685248 == 2^51的数字
其他回答
更新1:
刚刚意识到5 ^ 1074不是你可以从IEEE 754双精度浮点中免费得到的真正上限,因为我只计算了非规整指数,忘记了尾数本身可以适合另外22次5的事实,所以据我所知,一个人可以从双精度格式中免费得到的5的最大次幂是:
5的最大次方:
5 ^ 1096
最大奇数:
5 ^ 1074 x 9007199254740991 5 ^ 1074 x (2 ^ 53 - 1)
开始 CONVFMT =“IEEE754: 4字节word: %.16lX”; print”“, sprintf(%。”* g ", __=(_+=_+=_^=_<_)^++_+_*(_+_), {1ch88ff88} {1ch88ff88} {1ch88ff88} {1ch88ff88} {1ch88ff88} {1ch88ff88} {1ch88ff88} {1ch88ff88} {1ch88ff88} ' sprintf(* * %。g ",__,_=_*((_+=(_^=!_)+(_+=_))*_\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ' sprintf(%。”* g ",__,_=___*= \ (_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
4.940656458412465441765687928682213723650598026143247644255856825006755072702087518652998363616359923797965646954457177309266567103559397963987747960107818781263007131903114045278458171678489821036887186360569987307230500063874091535649843873124733972731696151400317153853980741262385655911710266585566867681870395603106249319452715914924553293054565444011274801297099995419319894090804165633245247571478690147267801593552386115501348035264934720193790268107107491703332226844753335720832431936092382893458368060106011506169809753078342277318329247904982524730776375927247874656084778203734469699533647017972677717585125660551199131504891101451037862738167250955837389733598993664809941164205702637090279242767544565229087538682506419718265533447265625e-324 — IEEE754 :: 4-byte word :: 0000000000000001 494065645841246544176568792......682506419718265533447265625 } 751 dgts : 5^1,074
1.1779442926436580280698985883431944188238616052015418158187524855152976686244219586021896275559329804892458073984282439492384355315111632261247033977765604928166883306272301781841416768261169960586755720044541328685833215865788678015827760393916926318959465387821953663477851727634395732669139543975751084522891987808004020022041120326339133484493650064495265010111570347355174765803347028811562651566216206901711944564705815590623254860079132843479610128658074120767908637153514231969910697784644086106916351461663273587631725676246505444808791274797874748064938487833137213363849587926231550453981511635715193075144590522172925785791614297511667878003519179715722536405560955202126362715257889359212587458533154881546706053453699158950485070818103849887847900390625e-308 — IEEE754 :: 4-byte word :: 000878678326EAC9 117794429264365802806989858......070818103849887847900390625 } 767 dgts : 5^1,096
4.4501477170144022721148195934182639518696390927032912960468522194496444440421538910330590478162701758282983178260792422137401728773891892910553144148156412434867599762821265346585071045737627442980259622449029037796981144446145705102663115100318287949527959668236039986479250965780342141637013812613333119898765515451440315261253813266652951306000184917766328660755595837392240989947807556594098101021612198814605258742579179000071675999344145086087205681577915435923018910334964869420614052182892431445797605163650903606514140377217442262561590244668525767372446430075513332450079650686719491377688478005309963967709758965844137894433796621993967316936280457084866613206797017728916080020698679408551343728867675409720757232455434770912461317493580281734466552734375e-308 — IEEE754 :: 4-byte word :: 001FFFFFFFFFFFFF 445014771701440227211481959......317493580281734466552734375 } 767 dgts : 5^1,074 6361 69431 20394401
下面是一个快速的awk代码片段,它可以打印出2到1023的每一个正幂,5到1096的每一个正幂,以及它们的共同幂为零,对有和没有bigint库都进行了优化:
{m,g,n}awk' BEGIN {
CONVFMT = "%." ((_+=_+=_^=_<_)*_+--_*_++)(!++_) "g"
OFMT = "%." (_*_) "g"
if (((_+=_+_)^_%(_+_))==(_)) {
print __=_=\
int((___=_+=_+=_*=++_)^!_)
OFS = ORS
while (--___) {
print int(__+=__), int(_+=_+(_+=_))
}
__=((_+=_+=_^=!(__=_))^--_+_*_) substr("",_=__)
do {
print _+=_+(_+=_) } while (--__)
exit
} else { _=_<_ }
__=((___=_+=_+=++_)^++_+_*(_+_--))
_=_^(-(_^_--))*--_^(_++^_^--_-__)
_____=-log(_<_)
__^=_<_
___=-___+--___^___
while (--___) {
print ____(_*(__+=__+(__+=__))) }
do {
print ____(_) } while ((_+=_)<_____)
}
function ____(__,_) {
return (_^=_<_)<=+__ \
? sprintf( "%.f", __) \
: substr("", _=sprintf("%.*g", (_+=++_)^_*(_+_),__),
gsub("^[+-]*[0][.][0]*|[.]|[Ee][+-]?[[:digit:]]+$","",_))_
}'
= = = = = = = = = = = = = = = = = = = = = = = = = = = = =
这取决于你对"有表征的"和"可表征的"的定义有多灵活
不管典型文献怎么说,在IEEE 754双精度中实际上“最大”的整数,没有任何大int库或外部函数调用,具有完全完整的尾数,是可计算、可存储和可打印的:
9,007,199,254,740,991 * 5 ^ 1074(~2546.750773909…比特)
4450147717014402272114819593418263951869639092703291
2960468522194496444440421538910330590478162701758282
9831782607924221374017287738918929105531441481564124
3486759976282126534658507104573762744298025962244902
9037796981144446145705102663115100318287949527959668
2360399864792509657803421416370138126133331198987655
1545144031526125381326665295130600018491776632866075
5595837392240989947807556594098101021612198814605258
7425791790000716759993441450860872056815779154359230
1891033496486942061405218289243144579760516365090360
6514140377217442262561590244668525767372446430075513
3324500796506867194913776884780053099639677097589658
4413789443379662199396731693628045708486661320679701
7728916080020698679408551343728867675409720757232455
434770912461317493580281734466552734375
我使用xxhash将其与gnu-bc进行比较,并确认它确实是相同的,没有精度损失。这个数字没有任何“非规格化”的地方,尽管指数范围被这样标记。
如果你不相信,在你自己的系统上试试。(我通过现成的mawk得到了这个打印)-你也可以很容易地得到它:
一(1)次幂/幂(^ aka **) op, 一个(1)乘(*)运算, 一次(1)sprintf()调用,和 任一(一)项 - substr()或regex-gsub() 执行必要的清理
就像我们经常提到的1.79…E309数字,
都是尾数有限公司 两者都是指数受限的 两者都有大得离谱的ulp(最后一名) 两者都距离浮点单元的溢出或下溢只有一步之遥,可以返回一个可用的答案
对工作流的二进制指数进行否定,您可以完全在这个空间中完成操作,然后在工作流的尾部再次反转它,以回到我们通常认为的“较大”的一侧,
但要记住,这是倒置的 指数领域,不存在“逐渐溢出”
- 4Chan出纳员
正如其他人所指出的,我将假设OP要求最大的浮点值,以便所有小于其本身的整数都可以精确表示。
你可以使用float.h中定义的FLT_MANT_DIG和DBL_MANT_DIG来不依赖于显式值(例如,53):
#include <stdio.h>
#include <float.h>
int main(void)
{
printf("%d, %.1f\n", FLT_MANT_DIG, (float)(1L << FLT_MANT_DIG));
printf("%d, %.1lf\n", DBL_MANT_DIG, (double)(1L << DBL_MANT_DIG));
}
输出:
24, 16777216.0
53, 9007199254740992.0
的确,对于64位的IEEE754双精度,所有到9007199254740992 == 2^53的整数都可以精确表示。
然而,值得一提的是,所有超出4503599627370496 == 2^52的可表示数字都是整数。 超过2^52,测试它们是否是整数就没有意义了,因为它们都隐式舍入到附近一个可表示的值。
在2^51到2^52的范围内,唯一的非整数值是以“”结尾的中点。5”,这意味着计算后的任何整数测试都必须产生至少50%的错误答案。
在2^51以下也有"25"和"。75英寸,所以比较一个数字和它的四舍五入的对应数字,以确定它是否可能是整数开始是有意义的。
TLDR:如果您想测试计算结果是否可能是整数,请避免大于2251799813685248 == 2^51的数字
在IEEE 754 double(64位)中可以表示的最大整数与该类型可以表示的最大值相同,因为该值本身就是一个整数。
这表示为0x7FEFFFFFFFFFFFFF,它由:
符号位0(正)而不是1(负) 最大指数0x7FE(2046表示减去偏差后的1023)而不是0x7FF(2047表示NaN或无穷大)。 最大尾数0xFFFFFFFFFFFFF是52位全1。
在二进制中,值是隐式的1,后面是尾数中的另外52个1,然后是指数中的971个0(1023 - 52 = 971)。
精确的十进制值为:
179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464 234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559 332123348274797826204144723168738177180919299881250404026184124858368
这大约是1.8 x 10308。
9007199254740992(即9,007,199,254,740,992或2^53),没有保证:)
程序
#include <math.h>
#include <stdio.h>
int main(void) {
double dbl = 0; /* I started with 9007199254000000, a little less than 2^53 */
while (dbl + 1 != dbl) dbl++;
printf("%.0f\n", dbl - 1);
printf("%.0f\n", dbl);
printf("%.0f\n", dbl + 1);
return 0;
}
结果
9007199254740991 9007199254740992 9007199254740992