avoiding integer overflow in symbolic calculations?
stevengj opened this issue · 2 comments
This is an example from our matrix calculus class that worked in SymPy but is failing with Symbolics:
function Babylonian(x; N = 10)
t = (1+x)/2
for i = 2:N; t=(t + x/t)/2 end
t
end
using Symbolics
@variables x
simplify(Babylonian(x,N=4))
which gives
julia> simplify(Babylonian(x,N=4))
ERROR: OverflowError: -11118795390271 * 4572599641 overflowed for type Int64
followed by a long stacktrace.
Is there a way to tell Symbolics that I want it to use BigInt
arithmetic here? e.g. shouldn't (1+x)/2
use BigInt
if x
is symbolic?
It just follows Julia's rules, so (1+x)/2
uses regular integers but (1+x)/big(2)
uses BigInt.
function Babylonian(x; N = 10)
t = (1+x)/2
for i = 2:N; t=(t + x/t)/big(2) end
t
end
using Symbolics
@variables x
Symbolics.derivative(simplify(Babylonian(x,N=4)),x)
simplify(Symbolics.derivative(simplify(Babylonian(x,N=4)),x))
julia> Symbolics.derivative(simplify(Babylonian(x,N=4)),x)
(15 + 454x + 3003(x^2) + 6432(x^3) + 5005(x^4) + 1362(x^5) + 105(x^6)) / (128(1 + x)*((1//4) + (3//2)*x + (1//4)*(x^2))*((1//16) + (7//4)*x + (35//8)*(x^2) + (7//4)*(x^3) + (1//16)*(x^4))) - (128((1//4) + (3//2)*x + (1//4)*(x^2))*((1//16) + (7//4)*x + (35//8)*(x^2) + (7//4)*(x^3) + (1//16)*(x^4)) + 128(1 + x)*((1//4) + (3//2)*x + (1//4)*(x^2))*((7//4) + (35//4)*x + (21//4)*(x^2) + (1//4)*(x^3)) + 128(1 + x)*((3//2) + (1//2)*x)*((1//16) + (7//4)*x + (35//8)*(x^2) + (7//4)*(x^3) + (1//16)*(x^4)))*((15x + 227(x^2) + 1001(x^3) + 1608(x^4) + 1001(x^5) + 227(x^6) + 15(x^7)) / (16384((1 + x)^2)*(((1//4) + (3//2)*x + (1//4)*(x^2))^2)*(((1//16) + (7//4)*x + (35//8)*(x^2) + (7//4)*(x^3) + (1//16)*(x^4))^2)))
julia> simplify(Symbolics.derivative(simplify(Babylonian(x,N=4)),x))
(960.0 + 29056.0x + 438592.0(x^2) + 3.523328e+06(x^3) + 1.6168832e+07(x^4) + 4.342272e+07(x^5) + 7.0727424e+07(x^6) + 7.0659072e+07(x^7) + 4.3384384e+07(x^8) + 1.6060544e+07(x^9) + 3.474368e+06(x^10) + 396032.0(x^11) + 19072.0(x^12)) / (524288((1 + x)^2)*(((1//4) + (3//2)*x + (1//4)*(x^2))^2)*(((1//16) + (7//4)*x + (35//8)*(x^2) + (7//4)*(x^3) + (1//16)*(x^4))^2))
works, though the fact that the last simplify changes to floats is a bug. @shashi do you know why that might be happening?
Julia evaluation for (1+x)/2
behaves differently depending on the type of x
, so I'm not sure what you mean by "It just follows Julia's rules". I don't want to use (1+x)/BigInt(2)
because if x
is a Float64
I want to keep it in that precision instead of promoting to BigFloat
. You are forcing me to write a different Babylonian
method just for Symbolics.
What I would like would be a promotion rule (maybe enabled by a flag or a type of symbolic variable?), that allows one to use (1+x)/2
, and says that when you combine integers with a symbolic expression you want to keep everything exact (i.e. promote to BigInt
, use rationals, etcetera), ala Mathematica or SymPy.
Is there a way to attach a type to a symbolic variable? e.g. @variables x::Rational{BigInt}
would make it do promotion as if x
were an unknown value of that type, keeping all coefficients exact. The current behavior seems more like @variables x::Float64
(float coefficients) or @variables x::Rational{Int}
(overflow).