Yes, this is a foible of Windows: long
is only 32 bit even on machines with 64-bit words. Unix systems like Linux, macOS and FreeBSD, on the other hand, are properly 64-bit on 64-bit hardware.
Do you know is it possible to remove this 32bits limit in Windows?
I wonder why in Linux they have 64bits for precision and in Windows only 32bits (
I’m a Windows-guy and never tried Linux.
Is that defined by the C
specification?
As far as I remember the specification doesn’t link the ISA Bits to the number of bits of the data types.
According to Wikipedia C Data Types it shows:
So Windows is also proper. There is nothing “More Proper” in Linux with that regard.
The C spec defines minimum sizes for representations and allows a lot of latitude in implementations, which is why portable C code uses typedefs for specific type sizes that are specialized for each implementation with the preprocessor.
As you can see by my answer I was aware of that.
I was pointing my comment to @StefanKarpinski’s remark about Unix / Posix based OS being proper on that while Windows is not.
While in fact both are in compliance with the C
standards.
Yes, sorry, I took your question as literal rather than rhetorical without reading fully. Perhaps Stefan ought to have used a different word, such as intuitive or expected. The library in question ought to have used portability typedefs if it were intended to behave the same on windows.
Ehhh, it can both be compliant with C standards (which are really quite loose) and a half-ways 64-bit implementation. But this is quite the digression.
Back to MFPR, they clearly want to support some awful legacy systems as they don’t want to depend upon C99 or limits.h:
154
/* Note: mpfr_prec_t is currently limited to "long". This means that
155under MS Windows, the precisions are limited to about 2^31; however,
156these are already huge precisions, probably sufficient in practice
157on this platform. */
and
165
/* we could use "long long" under Windows 64 here, which can be tested
166with the macro _WIN64 according to
167https://sourceforge.net/p/predef/wiki/OperatingSystems/ */
and
174
/* Definition of precision limits without needing <limits.h> */
Please forgive my ignorance, but is {\pi^\pi}^\pi a constant with a meaningful application/meaning, or is this just to stress-test bigfloats?
If there is a practical application, it certainly doesn’t need this many digits, so I assume this is just a personal quest.
The only remotely practical application I can imagine might be for crypto key generation
Seems that using higher precision Julia packages I’ve discovered that log(gamma( is related to PI ;
per using SpecialFunctions and using Nemo ?
using Julia SpecialFunctions and Nemo seems I’ve discovered that loggamma(-1 + 0i) = Infinity - i*pi (a Complex number) .
Also Wolframalpha answer is incomplete About: loggamma(-1 + 0i) or logΓ(-1 + 0 i)
Try this link loggamma(-1 + 0i) - Wolfram|Alpha
and you’ll see Wolframalpha shows loggamma(-1 + 0i) = Infinity
However it seems I’ve discovered/uncovered that loggamma(-1 + 0i) = Infinity - i*pi (a Complex number) per the following :
## show using SpecialFunctions
## loggamma(-1 + 0i) = Infinity - i*pi (a Complex number)
julia> loggamma(-1+0im)
Inf - 3.141592653589793im
julia> imag(loggamma(-1+0im))/pi
-1.0
## Showing Effects of error propagation ?
julia> log(gamma(-1+0im))
Inf - 2.356194490192345im
## Reconfirmed suspicion via show using Nemo to 64 Bits / 18 Decimals
using Nemo # for arbitrary precision math calculations
CC = ComplexField(64)
julia> using Nemo
julia> CC = ComplexField(64)
Complex Field with 64 bits of precision and error bounds
julia> RR = RealField(64)
Real Field with 64 bits of precision and error bounds
julia> Nemo.lgamma(RR("-1") + CC("0"))
nan + i*[-3.141592653589793238 +/- 5.14e-19]
julia> Nemo.const_pi(RR)
[3.141592653589793239 +/- 5.96e-19]
–
Also here’s an analytical/symbolic equation question :
Is this the same or a different fact than the Euler Identity ?
Maybe start here Gamma, Beta, Erf > LogGamma[z]
Representations through more general functions >> Logarithm of the gamma function: Representations through more general functions (subsection 26/01)
An answer for the OP’s original question for High Precision calculations ; example code using Nemo providing Definable precision mathematics with error bounds ( ? aka statistical error bars ?)
using Nemo
RR = RealField(64)
julia> Nemo.const_pi(RR)
[3.141592653589793239 +/- 5.96e-19]
**## Part1 answer for the OP’s original question**
**julia> RR = RealField(128)**
**Real Field with 128 bits of precision and error bounds**
julia> Nemo.const_pi(RR)
[3.1415926535897932384626433832795028842 +/- 1.06e-38]
## [3.1415926535897932384626433832795028842 +/- 1.06e-38]
## https://math.tools/numbers/pi/100
## First 100 digits of pi **(Cross-check)**
## [3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679
**## Part2 answer for the OP’s original question**
julia> Nemo.const_pi(RR)^Nemo.const_pi(RR)^Nemo.const_pi(RR)
[1340164183006357435.29744912964013141 +/- 7.44e-18]
## **(Cross-check)** **Exponentiation parsed correctly as right associative**
julia> Nemo.const_pi(RR)^(Nemo.const_pi(RR)^Nemo.const_pi(RR))
[1340164183006357435.29744912964013141 +/- 7.44e-18]
Here’s a solution using IntervalArithmetic.jl
:
julia> using IntervalArithmetic
julia> @format midpoint 50; # output 50 digits, use midpoint representation
julia> @biginterval π ^ π ^ π
1340164183006357435.2974491296401314001461680594635 ± 7.1689136000960352466299617899547031251599704983668e-58
EDIT: Using Float64 gives
julia> @interval π ^ π ^ π
1340164183006362112 ± 90624
Noticed the OP post was for an extremely high number of significant figures,
so pushed Nemo.jl out further to 4096 bits which is over 1000 sig figs base10.
julia> using Nemo
julia> RR = RealField(4096) ## using Nemo.jl for Definable precision mathematics with error bars.
Real Field with 4096 bits of precision and error bounds
julia> Nemo.const_pi(RR)
[3.141592653589793238462 ... +/- 5.51e-1233]
julia> Nemo.const_pi(RR)^Nemo.const_pi(RR)^Nemo.const_pi(RR)
[1340164183006357435.297 ... +/- 4.12e-1212]
julia> using BenchmarkTools
julia> @benchmark Nemo.const_pi(RR)^Nemo.const_pi(RR)^Nemo.const_pi(RR)
BenchmarkTools.Trial:
memory estimate: 3.92 KiB
allocs estimate: 12
--------------
minimum time: 232.576 μs (0.00% GC)
median time: 238.957 μs (0.00% GC)
mean time: 245.541 μs (0.00% GC)
maximum time: 716.879 μs (0.00% GC)
--------------
samples: 10000
evals/sample: 1
julia> @time Nemo.const_pi(RR)^Nemo.const_pi(RR)^Nemo.const_pi(RR)
0.000317 seconds (12 allocations: 3.922 KiB)
What was surprising and was, even using 4096 bit reals, Nemo.jl had very little, almost not noticeable CPU usage and very slight additional memory allocations when it calculated more than 1000 sig figs. So wondering if Nemo is exploiting a shortcut or “magic” that might be implicitly hidden in the Nemo features listed here >> Getting Started · Nemo.jl
I don’t think this is that surprising. All the problems Op was talking about were with asking for 100k to 1B digits. 4k and 100k are very different (I should know. I’m a math major ).
Scales pretty well past that:
julia> using Nemo
julia> foreach(2 .^ (8:17)) do N
@show N
RR = RealField(N)
result = @btime Nemo.const_pi($RR)^Nemo.const_pi($RR)^Nemo.const_pi($RR)
@show result
println()
end
N = 256
3.412 μs (12 allocations: 656 bytes)
result = [1340164183006357435.2974491296401314150993749745734992377879275165860340926 +/- 2.20e-56]
N = 512
5.872 μs (12 allocations: 880 bytes)
result = [1340164183006357435.297449129640131415099374974573499237787927516586034092619094068148269472611301142273437488952597496949098445637468318932074814417133 +/- 1.27e-133]
N = 1024
16.670 μs (12 allocations: 1.30 KiB)
result = [1340164183006357435.29744912964013141509937497457349923778792751658603409261909406814826947261130114227343748895259749694909844563746831893207481441713296868595665505861832304409260344935722137619083399128209272634779708614451149209064907822294679198447533622596408302511181354428253415769627492356327900821 +/- 7.02e-288]
N = 2048
56.280 μs (12 allocations: 2.17 KiB)
result = [1340164183006357435.2974491296401314150993749745734992377879275165860340926190940681482694726113011422734374889525974969490984456374683189320748144171329686859566550586183230440926034493572213761908339912820927263477970861445114920906490782229467919844753362259640830251118135442825341576962749235632790082163382354493811048356977004050046461235433245632644834558130591134781891957097416354676228557308050967641819526522537994353891274135380086401090813607445243381831678464008385405226026792226019874421667534912237652417044112558499915127650180612214632249925590671652930224582813662674852983217955536851340666680 +/- 6.63e-596]
N = 4096
221.058 μs (12 allocations: 3.92 KiB)
result = [1340164183006357435.2974491[...] +/- 4.12e-1212]
N = 8192
800.201 μs (256 allocations: 42.52 KiB)
result = [1340164183006357435.2974491[...]+/- 4.83e-2445]
N = 16384
2.697 ms (468 allocations: 94.98 KiB)
result = [1340164183006357435.2974491[...] +/- 4.57e-4911]
N = 32768
8.819 ms (1570 allocations: 628.26 KiB)
result = [1340164183006357435.2974491[...] +/- 2.81e-9843]
N = 65536
25.970 ms (3409 allocations: 4.76 MiB)
result = [1340164183006357435.2974491[...] +/- 8.69e-19708]
N = 131072
76.024 ms (6554 allocations: 13.56 MiB)
result = [1340164183006357435.2974491[...] +/- 7.03e-39436]
(truncated digits so I would meet the maximum character count)
Edit: here’s how far I could go before each iteration was taking enough ram that I no longer wanted it running:
julia> foreach(2 .^ (18:25)) do N
@show N
RR = RealField(N)
result = @btime Nemo.const_pi($RR)^Nemo.const_pi($RR)^Nemo.const_pi($RR)
println()
end
N = 262144
222.262 ms (17277 allocations: 70.47 MiB)
N = 524288
601.466 ms (42648 allocations: 236.61 MiB)
N = 1048576
1.485 s (91724 allocations: 677.82 MiB)
N = 2097152
3.731 s (180055 allocations: 1.59 GiB)
N = 4194304
8.980 s (344271 allocations: 3.72 GiB)
N = 8388608
21.636 s (656866 allocations: 8.32 GiB)
So 8,388,608 digits, not bad.
Possibly that’s not a helpful or useful way of trying to understand it. People asked similar questions as every new extension to positive integers was introduced. There were objections to negative numbers, complex numbers etc. “How is it possible to have -5 apples? It’s not possible!” The meaning of what a number is was also extended.
What “is” 1^0 or 0^0? Such things are just defined to be whatever is most compatible with existing formulas, what it is most convenient they should be. Puzzling about it as if it makes no sense according to the previous definitions is needless confusion.
But…if you must, maybe try to understand square roots first! x^(1/2). Playing around with Newton’s generalised binomial formula for non-integer powers might help them make more sense.
using Nemo.jl works to over 157000 Base10 digits in less than 1 second. Definitely wondering now if Nemo is exploiting some mathematical shortcut “magic” that might be implicitly hidden in the Nemo features listed here >> Getting Started · Nemo.jl
julia> RR = RealField(524288) ## using Nemo.jl for Definable precision mathematics with error bars.
Real Field with 524288 bits of precision and error bounds
julia> @time Nemo.const_pi(RR)^Nemo.const_pi(RR)^Nemo.const_pi(RR)
0.658621 seconds (42.92 k allocations: 242.657 MiB, 1.31% gc time)
[1340164183006357435.297449 ... +/- 6.47 **e-157806** ]
## Typing aide shortcut below, beware you'll get a screenful lol
using Nemo
RR = RealField(524288) ## using Nemo.jl for Definable precision mathematics with error bars.
@time Nemo.const_pi(RR)^Nemo.const_pi(RR)^Nemo.const_pi(RR)
@time Nemo.const_pi(RR)^Nemo.const_pi(RR)^Nemo.const_pi(RR)
@Marc.Cox I believe it’s using Fredrik Johansson’s arb software. He has a nice paper describing how that works.
@dpsanders, this paper?