mirror of
https://github.com/dlang/phobos.git
synced 2025-04-29 06:30:28 +03:00
Fix Issue 21853 - std.format: formatting real.max in CTFE fails
This commit is contained in:
parent
0881660baf
commit
110cb1a8be
2 changed files with 39 additions and 12 deletions
|
@ -48,6 +48,7 @@ if (is(T == float) || is(T == double)
|
|||
import std.math.rounding : floor;
|
||||
import std.math.traits : isInfinity, isNaN;
|
||||
import std.math.exponential : log2;
|
||||
import std.math.operations : nextUp;
|
||||
|
||||
auto val2 = val;
|
||||
|
||||
|
@ -55,6 +56,8 @@ if (is(T == float) || is(T == double)
|
|||
exp = 32767;
|
||||
else if (abs(val2) < real.min_normal)
|
||||
exp = 0;
|
||||
else if (abs(val2) >= nextUp(real.max / 2))
|
||||
exp = 32766;
|
||||
else
|
||||
exp = cast(int) (val2.abs.log2.floor() + 16383);
|
||||
|
||||
|
@ -63,22 +66,31 @@ if (is(T == float) || is(T == double)
|
|||
// NaN or infinity
|
||||
mnt = isNaN(val2) ? ((1L << 63) - 1) : 0;
|
||||
}
|
||||
else if (exp > 16382 + 64) // bias + bits of ulong
|
||||
{
|
||||
val2 /= 2.0L ^^ (exp - (16382 + 64));
|
||||
mnt = (cast(ulong) abs(val2)) & ((1L << 63) - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto delta = 16382 + 64 - (exp == 0 ? 1 : exp); // -1 in case of subnormals
|
||||
if (delta > 16383)
|
||||
if (exp > 16382 + 64) // bias + bits of ulong
|
||||
val2 /= 2.0L ^^ (exp - (16382 + 64));
|
||||
else
|
||||
{
|
||||
// need two steps to avoid overflow
|
||||
val2 *= 2.0L ^^ 16383;
|
||||
delta -= 16383;
|
||||
auto delta = 16382 + 64 - (exp == 0 ? 1 : exp); // -1 in case of subnormals
|
||||
if (delta > 16383)
|
||||
{
|
||||
// need two steps to avoid overflow
|
||||
val2 *= 2.0L ^^ 16383;
|
||||
delta -= 16383;
|
||||
}
|
||||
val2 *= 2.0L ^^ delta;
|
||||
}
|
||||
val2 *= 2.0L ^^ delta;
|
||||
mnt = (cast(ulong) abs(val2)) & ((1L << 63) - 1);
|
||||
|
||||
ulong tmp = cast(ulong) abs(val2);
|
||||
if (exp != 32767 && exp > 0 && tmp <= ulong.max / 2)
|
||||
{
|
||||
// correction, due to log2(val2) being rounded up:
|
||||
exp--;
|
||||
val2 *= 2.0L;
|
||||
tmp = cast(ulong) abs(val2);
|
||||
}
|
||||
mnt = tmp & ((1L << 63) - 1);
|
||||
}
|
||||
|
||||
double d = cast(double) val2;
|
||||
|
|
|
@ -918,6 +918,21 @@ if (is(FloatingPointTypeOf!T) && !is(T == enum) && !hasToString!(T, Char))
|
|||
}
|
||||
}
|
||||
|
||||
// https://issues.dlang.org/show_bug.cgi?id=21853
|
||||
@safe pure unittest
|
||||
{
|
||||
import std.math.exponential : log2;
|
||||
|
||||
// log2 is broken for x87-reals on some computers in CTFE
|
||||
// the following test excludes these computers from the test
|
||||
// (issue 21757)
|
||||
enum test = cast(int) log2(3.05e2312L);
|
||||
static if (real.mant_dig == 64 && test == 7681) // 80 bit reals
|
||||
{
|
||||
static assert(format!"%e"(real.max) == "1.189731e+4932");
|
||||
}
|
||||
}
|
||||
|
||||
// https://issues.dlang.org/show_bug.cgi?id=20536
|
||||
@safe pure unittest
|
||||
{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue