issue 7006 - std.math.pow (integral, integral) crashes on negative exponents
Timon Gehr
timon.gehr at gmx.ch
Tue Dec 17 15:40:03 UTC 2019
On 17.12.19 16:07, Dominikus Dittes Scherkl wrote:
> On Tuesday, 17 December 2019 at 14:26:42 UTC, Timon Gehr wrote:
>> On 17.12.19 14:39, Dominikus Dittes Scherkl wrote:
>>> ^^ should result in a real if the exponent is outside ubyte range.
>>> Is this wrong?
>>
>> Yes.
> Why?
It's neither sound nor complete, you can't even enforce it in a precise
manner and it defies expectations.
Let's say I write:
auto foo(T...)(T args){
// ...
return a^^(b?2:3)
}
Someone comes along that has a dislike for ternary operators and my
formatting preferences and refactors the code to the obviously equivalent
auto foo(T...)(T args)
{
// ... (rename "a" to "base")
int exponent; // typeof(2) = typeof(3) = int
if (b)
{
exponent = 2;
}
else
{
exponent = 3;
}
return base^^exponent;
}
Now suddenly my program starts to implicitly use `real` computations all
over the place, potentially creating wrong outputs and producing
different results on different machines.
Thanks, but no. Emphatically. This is a terrible idea.
It's highly likely that the result is out of range or is a fraction.
> A floatginpoint value would give much more useful information.
>
>> There are reasonable outputs for the entire range of each individual
>> argument.
>
> If you look at it from mathematical point of view:
> pow is defined as a mapping
> ℕ × ℕ → ℕ
> but if we extend it to
> ℤ × ℤ → ℤ
There's no such thing.
> we have undefined points, because 1/n is not in ℤ for all n>1.
Or for n=0.
> Maybe it is convenient to return 0 in such cases, but not correct.
> Throwing is more plausible, if restricting to ℤ × ℕ → ℤ or
> extending to ℤ × ℤ → ℚ is wrong as you state above.
> ...
uint is not ℕ, int is not ℤ, real is not ℚ, and unsigned types don't
help prevent programming errors (the opposite is the case). Also, you
can't extend xʸ to ℤ×ℤ→ℚ.
>> I'd highly prefer it to consistently return 0 rather than kill my
>> program without a stack trace. However, I agree that this case is
>> slightly less clear-cut.
> At least it is not what I would call "consistent".
> ...
x⁻¹ = 1/x. 1/2 = 0. 2^^-1 = 0. Consistent.
The interpretation ⟦.⟧ of integer division admits:
⟦a/b⟧=truncate(⟦a⟧/⟦b⟧) in case (⟦a⟧,⟦b⟧) and truncate(⟦a⟧/⟦b⟧) are in
range.
Therefore it is consistent to say:
⟦a^^b⟧=truncate(⟦a⟧^^⟦b⟧) in case (⟦a⟧,⟦b⟧) and truncate(⟦a⟧^^⟦b⟧) are
in range.
More information about the Digitalmars-d
mailing list