mirror of
https://github.com/dlang/phobos.git
synced 2025-04-30 15:10:46 +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.rounding : floor;
|
||||||
import std.math.traits : isInfinity, isNaN;
|
import std.math.traits : isInfinity, isNaN;
|
||||||
import std.math.exponential : log2;
|
import std.math.exponential : log2;
|
||||||
|
import std.math.operations : nextUp;
|
||||||
|
|
||||||
auto val2 = val;
|
auto val2 = val;
|
||||||
|
|
||||||
|
@ -55,6 +56,8 @@ if (is(T == float) || is(T == double)
|
||||||
exp = 32767;
|
exp = 32767;
|
||||||
else if (abs(val2) < real.min_normal)
|
else if (abs(val2) < real.min_normal)
|
||||||
exp = 0;
|
exp = 0;
|
||||||
|
else if (abs(val2) >= nextUp(real.max / 2))
|
||||||
|
exp = 32766;
|
||||||
else
|
else
|
||||||
exp = cast(int) (val2.abs.log2.floor() + 16383);
|
exp = cast(int) (val2.abs.log2.floor() + 16383);
|
||||||
|
|
||||||
|
@ -63,22 +66,31 @@ if (is(T == float) || is(T == double)
|
||||||
// NaN or infinity
|
// NaN or infinity
|
||||||
mnt = isNaN(val2) ? ((1L << 63) - 1) : 0;
|
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
|
else
|
||||||
{
|
{
|
||||||
auto delta = 16382 + 64 - (exp == 0 ? 1 : exp); // -1 in case of subnormals
|
if (exp > 16382 + 64) // bias + bits of ulong
|
||||||
if (delta > 16383)
|
val2 /= 2.0L ^^ (exp - (16382 + 64));
|
||||||
|
else
|
||||||
{
|
{
|
||||||
// need two steps to avoid overflow
|
auto delta = 16382 + 64 - (exp == 0 ? 1 : exp); // -1 in case of subnormals
|
||||||
val2 *= 2.0L ^^ 16383;
|
if (delta > 16383)
|
||||||
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;
|
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
|
// https://issues.dlang.org/show_bug.cgi?id=20536
|
||||||
@safe pure unittest
|
@safe pure unittest
|
||||||
{
|
{
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue