特定值的幂运算符问题
Problem with power operator for specific values
我正在尝试做一个简单的函数来检查阶乘和斯特林近似之间的差异:
using DataFrames
n = 24
df_res = DataFrame(i = BigInt[],
f = BigInt[],
st = BigInt[])
for i in 1:n
fac = factorial(big(i))
sterling = i^i*exp(-i)*sqrt(i)*sqrt(2*pi)
res = DataFrame(i = [i],
f = [fac],
st = [sterling])
df_res = [df_res;res]
end
first(df_res, 24)
当i=16和i=24时英镑的结果是0!。所以,我检查了两个值的幂,结果是 0:
julia> 16^16
0
julia> 24^24
0
我在 R 中编写了相同的代码,没有任何问题。我做错了什么或者我对 Julia 不了解,我可能应该了解什么?
根据 Integers and Floating-Point Numbers 的 Julia 文档,Julia 整数似乎是 32 位或 64 位,具体取决于您的系统。你的求幂溢出了你的值,即使它们是 64 位的。
Julia 看起来支持 Arbitrary Precision Arithmetic,您需要用它来存储较大的结果值。
根据 Overflow Section,写 big(n)
使得 n
任意精度。
虽然问题已经在另一个 post 上得到了回答,但还有一件事值得一提。
Julia 是为数不多的允许您定义自己的原始类型的语言之一 - 因此您仍然可以使用快速固定精度的数字来处理巨大的值。有一个包 BitIntegers
:
BitIntegers.@define_integers 512
现在您可以:
julia> Int512(2)^500
3273390607896141870013189696827599152216642046043064789483291368096133796404674554883270092325904157150886684127560071009217256545885393053328527589376
通常,即使是大的定点算术数,您也会获得更好的性能。例如:
julia> @btime Int512(2)^500;
174.687 ns (0 allocations: 0 bytes)
julia> @btime big(2)^500;
259.643 ns (9 allocations: 248 bytes)
有一个简单的解决方案可以解决您的问题,它不涉及使用 BigInt
或任何专门的数字类型,而且速度要快得多。只需稍微调整您的数学表达式即可。
foo(i) = i^i*exp(-i)*sqrt(i)*sqrt(2*pi) # this is your function
bar(i) = (i / exp(1))^i * sqrt(i) * sqrt(2*pi) # here's a better way
好的,我们来测试一下:
1.7.2> foo(16)
0.0 # oops. not what we wanted
1.7.2> foo(big(16)) # works
2.081411441522312838373895982304611417026205959453251524254923609974529540404514e+13
1.7.2> bar(16) # also works
2.0814114415223137e13
让我们尝试计时:
1.7.2> using BenchmarkTools
1.7.2> @btime foo(n) setup=(n=16)
18.136 ns (0 allocations: 0 bytes)
0.0
1.7.2> @btime foo(n) setup=(n=big(16))
4.457 μs (25 allocations: 1.00 KiB) # horribly slow
2.081411441522312838373895982304611417026205959453251524254923609974529540404514e+13
1.7.2> @btime bar(n) setup=(n=16)
99.682 ns (0 allocations: 0 bytes) # pretty fast
2.0814114415223137e13
编辑:好像是
baz(i) = float(i)^i * exp(-i) * sqrt(i) * sqrt(2*pi)
可能是更好的解决方案,因为数值更接近原始值。
我正在尝试做一个简单的函数来检查阶乘和斯特林近似之间的差异:
using DataFrames
n = 24
df_res = DataFrame(i = BigInt[],
f = BigInt[],
st = BigInt[])
for i in 1:n
fac = factorial(big(i))
sterling = i^i*exp(-i)*sqrt(i)*sqrt(2*pi)
res = DataFrame(i = [i],
f = [fac],
st = [sterling])
df_res = [df_res;res]
end
first(df_res, 24)
当i=16和i=24时英镑的结果是0!。所以,我检查了两个值的幂,结果是 0:
julia> 16^16
0
julia> 24^24
0
我在 R 中编写了相同的代码,没有任何问题。我做错了什么或者我对 Julia 不了解,我可能应该了解什么?
根据 Integers and Floating-Point Numbers 的 Julia 文档,Julia 整数似乎是 32 位或 64 位,具体取决于您的系统。你的求幂溢出了你的值,即使它们是 64 位的。
Julia 看起来支持 Arbitrary Precision Arithmetic,您需要用它来存储较大的结果值。
根据 Overflow Section,写 big(n)
使得 n
任意精度。
虽然问题已经在另一个 post 上得到了回答,但还有一件事值得一提。
Julia 是为数不多的允许您定义自己的原始类型的语言之一 - 因此您仍然可以使用快速固定精度的数字来处理巨大的值。有一个包 BitIntegers
:
BitIntegers.@define_integers 512
现在您可以:
julia> Int512(2)^500
3273390607896141870013189696827599152216642046043064789483291368096133796404674554883270092325904157150886684127560071009217256545885393053328527589376
通常,即使是大的定点算术数,您也会获得更好的性能。例如:
julia> @btime Int512(2)^500;
174.687 ns (0 allocations: 0 bytes)
julia> @btime big(2)^500;
259.643 ns (9 allocations: 248 bytes)
有一个简单的解决方案可以解决您的问题,它不涉及使用 BigInt
或任何专门的数字类型,而且速度要快得多。只需稍微调整您的数学表达式即可。
foo(i) = i^i*exp(-i)*sqrt(i)*sqrt(2*pi) # this is your function
bar(i) = (i / exp(1))^i * sqrt(i) * sqrt(2*pi) # here's a better way
好的,我们来测试一下:
1.7.2> foo(16)
0.0 # oops. not what we wanted
1.7.2> foo(big(16)) # works
2.081411441522312838373895982304611417026205959453251524254923609974529540404514e+13
1.7.2> bar(16) # also works
2.0814114415223137e13
让我们尝试计时:
1.7.2> using BenchmarkTools
1.7.2> @btime foo(n) setup=(n=16)
18.136 ns (0 allocations: 0 bytes)
0.0
1.7.2> @btime foo(n) setup=(n=big(16))
4.457 μs (25 allocations: 1.00 KiB) # horribly slow
2.081411441522312838373895982304611417026205959453251524254923609974529540404514e+13
1.7.2> @btime bar(n) setup=(n=16)
99.682 ns (0 allocations: 0 bytes) # pretty fast
2.0814114415223137e13
编辑:好像是
baz(i) = float(i)^i * exp(-i) * sqrt(i) * sqrt(2*pi)
可能是更好的解决方案,因为数值更接近原始值。