# Representing very big numbers

How can I perform arithmetic on numbers on the order of a googloplex i.e. `10^(10^100)`?

I don’t have enough memory to express them exactly as integers with all their digits, but I’d like to be able to represent them as `BigFloat`s. The largest I’ve been able to get is approximately `10^(10^18)`:

``````n = round(Int, log10(2) * typemax(Int) / 2) - 14
parse(BigFloat, "5.87565378911158759093691e+\$n")
``````
1 Like

yeah. `BigFloat` maxes out at `2^(2^62)`. If you want bigger numbers than that, you would need a different number type.

2 Likes

Do you know of any packages that provide types with higher maxima?

`ArbFloat` goes up to 2^(2^126) (about 10^10^37).

2 Likes

I see it maxing out just under half that: `2^(2^62-1)`

``````julia> big(2.0)^(2^62-2) * 2
Inf

julia> big(2.0)^(2^62-2) * 1.99999999999999
5.875653789111558236149365709100443785085523336097068334320279213651249557023989e+1388255822130839282
``````

yeah, i was giving a somewhat rough number.

1 Like

Maybe LogarithmicNumbers can help?

``````julia> m = exp(ULogarithmic, floatmax(BigFloat))
exp(5.875653789111587590936911998878442589938516392745498308333779606469323584389875e+1388255822130839282)

julia> log10(log10(m))
1.388255822130839282406840509258088745814167339601572288185265795534139656091031e+18
``````

I think this should cover your case, but I get

``````julia> ten = ULogarithmic(big(10.0))
exp(2.302585092994045684017991454684364207601101488628772976033327900967572609677367)

julia> ten^(ten^100)
ERROR: StackOverflowError:
Stacktrace:
 promote_type(#unused#::Type{BigFloat}, #unused#::Type{Logarithmic{BigFloat}})
@ Base ./promotion.jl:298
 promote_result(#unused#::Type, #unused#::Type, #unused#::Type{BigFloat}, #unused#::Type{Logarithmic{BigFloat}})
@ Base ./promotion.jl:312
--- the last 2 lines are repeated 39990 more times ---
 promote_type(#unused#::Type{BigFloat}, #unused#::Type{Logarithmic{BigFloat}})
@ Base ./promotion.jl:298
``````

@cjdoris , do you have any ideas for addressing this?

EDIT: I added an issue: Problems with big numbers · Issue #12 · cjdoris/LogarithmicNumbers.jl · GitHub

1 Like

This feels like the right answer, but it does not work for my use case (`SpecialFunctions.loggamma`).

``````julia> loggamma(ULogarithmic(10)^(10^3))
Inf

julia> loggamma(big(10.0)^(10^18))
2.302585092994045683017991454684364207601101488628772976033327900967572609677336e+1000000000000000018
``````

I’m not sure if this is a bug or an unavoidable artifact of the fact that these numbers are backed by only 64 bits.

`loggamma` is defined as

``````loggamma(x::Number) = _loggamma(float(x))
``````

But in this case, `float(x)` returns `Inf`. I think you’ll need a new `loggamma` method to do this. Maybe you can modify the SpecialFunctions implementation for this type?

I think I’d use an approximation, and just make sure the error is small enough for your purposes. A good starting point is Stirling’s approximation, and there are some alternatives in the links toward the bottom. It’s especially handy that the relative error decreases with the size of the argument, so you might end up needing only a couple of terms.

1 Like

The issue is that loggamma is defined via ccalls rather than wholly in Julia. If it were Julia all the way down, I would expect ULogarithmic’s implementations of primitives would make it work without modification.

Lol no way.

Here’s an implementation of Stirling’s approximation (the `oftype`s should not be required but work around the stack overflow reported above):

``````julia> using LogarithmicNumbers

julia> approxloggamma(x) = (
x * oftype(x, log(x) - 1)
- oftype(x, log(x) / 2)
+ 1/12x - 1/360x^3 + 1/1260x^5
)
approxloggamma (generic function with 1 method)

julia> approxloggamma(exp(ULogarithmic, 1e100))
+exp(1.0e100)

julia> setprecision(BigFloat, 1000)
1000

julia> approxloggamma(exp(ULogarithmic, big"1e100"))
+exp(1.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002302585092994045684017991454684364207601101488628772976033327900967572609677352480235997205089598298340967784042286248633409525465082806756666287369098781689482907208325554680843799894826233198528393505266e+100)
``````

(Accurate to o(x^5) plus floating point precision.)

1 Like
``````approxloggamma(x::T) where {T} = (
x * oftype(x, log(x) - 1)
- oftype(x, log(x) / 2)
+ evalpoly(inv(x), (inv(T(12)), inv(T(360)), inv(T(1260)))
)
``````

In fact

``````approxloggamma(x) = x * oftype(x, log(x) - 1)
``````

is correct to O(\log x), which is already far more accurate than the precision you’ll ever represent it to.

1 Like

What is the use case?

To quickly compute the limit as `n` goes to infinity of `2n*log(n) / log2(factorial(n))`. I was able to compute the value to 64-bit floating point precision, pasted it into Google, and found this post which led me to conclude that the closed form answer is `log(4)`. After getting this closed form, I continued on pencil and paper.

Beyond that already resolved use-case, this is a theoretical question.

1 Like

Wolfram Alpha is useful for this kind of query.

2 Likes

I haven’t bought the Pro so I cannot see the full solution, but it seems apparent that the limit was found by manipulating the math expression, not by actually computing values for large `n`. The largest `n` represented by all the software bits in the world is nothing compared to infinity, who knows if the value converges or diverges past there.