It looks like you have to program it yourself. At a boundary x == 2.^n, the distance to the next machine real is either x * $MachineEpsilon or x * $MachineEpsilon / 2. The documentation for MantissaExponent ambiguously states that the mantissa will be "between $1/b$ and $1$". It seems be the case that $1/b \le \mathtt{mantissa} < 1$.
nextafter[0., y_] := Sign[y] $MinMachineNumber;
nextafter[x_, y_] /; Precision[x] == MachinePrecision :=
With[{mantexp = MantissaExponent[x, 2]},
Piecewise[{
{First[mantexp] + Sign[y] $MachineEpsilon/4.,
Sign[x] Sign[y] < 0 && First[mantexp] == 1./2.}},
First[mantexp] + Sign[y] $MachineEpsilon/2.] * 2.^Last[mantexp]
];
A couple of tests:
Block[{x = 128. - 128*$MachineEpsilon/2},
Print @ RealDigits[{nextafter[x, -1], x, nextafter[x, 1]}, 2];
Differences[{nextafter[x, -1], x, nextafter[x, 1]}]
]
(*
{{{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 0}, 7},
{{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1}, 7},
{{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0}, 8}}
{1.42109*10^-14, 1.42109*10^-14}
*)
Block[{x = 128.},
Print @ RealDigits[{nextafter[x, -1], x, nextafter[x, 1]}, 2];
Differences[{nextafter[x, -1], x, nextafter[x, 1]}]
]
(*
{{{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1}, 7},
{{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0}, 8},
{{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 1}, 8}}
{1.42109*10^-14, 2.84217*10^-14}
*)
To deal with subnormal numbers, one has to use Compile, ASAIK.
nextafter = With[{min = $MinMachineNumber},
Compile[{x, y},
Block[{e, laste},
If[x == 0,
Sign[y] min/2.^52,
If[x < 1,
e = 2.^(Ceiling @ Log2 @ Abs[x] + 52);
laste = e*2^-52,
laste = e = 2.^Ceiling[Log2 @ Abs[x] - 52]];
While[x + Sign[y] e != x,
laste = e; e = e/2.];
x + Sign[y] laste]],
RuntimeOptions -> {"CompareWithTolerance" -> False}]]
You'll get an error on $MaxMachineNumber depending on the direction. I hope I haven't tripped over any other boundary traps.
x + Sign[y] $MachineEpsilonshould work, yes? – J. M.'s missing motivation May 24 '15 at 04:55$MachineEpsilonis the smallest floating-point number such that1 + $MachineEpsilon != 1, but for certain values, the distance to the next representable float is much smaller. For example, consider the distance between1.0e-300and the next number up. – David Zhang May 24 '15 at 04:56Ulpet al. in the Computer Arithmetic package... – ciao May 24 '15 at 05:281.0e300and the next floating-point value is a lot larger than$MachineEpsilon. In general, the gaps between consecutive floating-point numbers change with the magnitude of the numbers. – David Zhang May 24 '15 at 05:41Ulpis definitely a step in the right direction, but I'm not sure how to use it to implementnextafter. In particuar, I'm not sure how to handle the transitions between one exponent value and the next; note that1.0 + Ulp[1.0] == 1.0while1.0 - Ulp[1.0] != 1.0. – David Zhang May 24 '15 at 05:42{IntegerPart[#1/$MachineEpsilon], #2} & @@ MantissaExponent[x, 2]to split the floating point number to integer-valued components and working further with those. – kirma May 24 '15 at 05:43