Julia 整數(shù)和浮點數(shù)

2022-02-25 15:45 更新

整數(shù)和浮點數(shù)是算術(shù)和計算的基礎(chǔ)。它們都是數(shù)字文本。例如 1 是整數(shù)文本, 1.0 是浮點數(shù)文本。

Julia 提供了豐富的基礎(chǔ)數(shù)值類型,全部的算數(shù)運算符和位運算符,以及標(biāo)準(zhǔn)數(shù)學(xué)函數(shù)。這些數(shù)據(jù)和操作直接對應(yīng)于現(xiàn)代計算機支持的操作。因此, Julia 能充分利用硬件的計算資源。另外, Julia 還從軟件層面支持任意精度的算術(shù) ,可以用于表示硬件不能原生支持的數(shù)值,當(dāng)然,這犧牲了部分運算效率。

Julia 提供的基礎(chǔ)數(shù)值類型有:

  • 整數(shù)類型

Char 原生支持 Unicode 字符 ;詳見字符串 。

浮點數(shù)類型:

類型 精度 位數(shù)
Float16 半精度 16
Float32 單精度 32
Float64 雙精度 64

另外, 對復(fù)數(shù)和分?jǐn)?shù)的支持建立在這些基礎(chǔ)數(shù)據(jù)類型之上。所有的基礎(chǔ)數(shù)據(jù)類型通過靈活用戶可擴展的類型提升系統(tǒng)不需顯式類型轉(zhuǎn)換,就可以互相運算。

整數(shù)

使用標(biāo)準(zhǔn)方式來表示文本化的整數(shù):

julia> 1
1

julia> 1234
1234

整數(shù)文本的默認(rèn)類型,取決于目標(biāo)系統(tǒng)是 32 位架構(gòu)還是 64 位架構(gòu):

# 32-bit system:
julia> typeof(1)
Int32

# 64-bit system:
julia> typeof(1)
Int64
Julia 內(nèi)部變量 `WORD_SIZE` 用以指示目標(biāo)系統(tǒng)是 32 位還是 64 位.

# 32-bit system:
julia> WORD_SIZE
32

# 64-bit system:
julia> WORD_SIZE
64

另外,Julia 定義了 IntUint 類型,它們分別是系統(tǒng)原生的有符號和無符號整數(shù)類型的別名:

# 32-bit system:
julia> Int
Int32
julia> Uint
Uint32

# 64-bit system:
julia> Int
Int64
julia> Uint
Uint64

對于不能用 32 位而只能用 64 位來表示的大整數(shù)文本,不管系統(tǒng)類型是什么,始終被認(rèn)為是 64 位整數(shù):

# 32-bit or 64-bit system:
julia> typeof(3000000000)
Int64

無符號整數(shù)的輸入和輸出使用前綴 0x 和十六進(jìn)制數(shù)字 0-9a-f (也可以使用 A-F )。無符號數(shù)的位數(shù)大小,由十六進(jìn)制數(shù)的位數(shù)決定:

julia> 0x1
0x01

julia> typeof(ans)
Uint8

julia> 0x123
0x0123

julia> typeof(ans)
Uint16

julia> 0x1234567
0x01234567

julia> typeof(ans)
Uint32

julia> 0x123456789abcdef
0x0123456789abcdef

julia> typeof(ans)
Uint64

二進(jìn)制和八進(jìn)制文本:

julia> 0b10
0x02

julia> typeof(ans)
Uint8

julia> 0o10
0x08

julia> typeof(ans)
Uint8

基礎(chǔ)數(shù)值類型的最小值和最大值,可由 typemintypemax 函數(shù)查詢:

julia> (typemin(Int32), typemax(Int32))
(-2147483648,2147483647)

julia> for T = {Int8,Int16,Int32,Int64,Int128,Uint8,Uint16,Uint32,Uint64,Uint128}
         println("$(lpad(T,7)): [$(typemin(T)),$(typemax(T))]")
       end
   Int8: [-128,127]
  Int16: [-32768,32767]
  Int32: [-2147483648,2147483647]
  Int64: [-9223372036854775808,9223372036854775807]
 Int128: [-170141183460469231731687303715884105728,170141183460469231731687303715884105727]
  Uint8: [0,255]
 Uint16: [0,65535]
 Uint32: [0,4294967295]
 Uint64: [0,18446744073709551615]
Uint128: [0,340282366920938463463374607431768211455]

typemintypemax 的返回值,與所給的參數(shù)類型是同一類的。(上述例子用到了一些將要介紹到的特性,包括 for 循環(huán) ,字符串 ,及內(nèi)插 。)

溢出

在 Julia 中,如果計算結(jié)果超出數(shù)據(jù)類型所能代表的最大值,將會發(fā)生溢出:

julia> x = typemax(Int64)
9223372036854775807

julia> x + 1
-9223372036854775808

julia> x + 1 == typemin(Int64)
true

可見, Julia 中的算數(shù)運算其實是一種同余算術(shù) 。它反映了現(xiàn)代計算機底層整數(shù)算術(shù)運算特性。如果有可能發(fā)生溢出,一定要顯式的檢查是否溢出;或者使用 BigInt 類型(詳見任意精度的算術(shù) )。

為了減小溢出所帶來的影響,整數(shù)加減法、乘法、指數(shù)運算都會把原先范圍較小的整數(shù)類型提升到 IntUint 類型。(除法、求余、位運算則不提升類型)。

除法錯誤

整數(shù)除法(div 功能)有兩個額外的樣例:被 0 除,和被最低的負(fù)數(shù)(typemin)-1 除。兩個例子都拋出了一個 DivideError。余數(shù)和模運算(remmod)當(dāng)它們的第二個參數(shù)為 0 時,拋出了一個 DivideError。

浮點數(shù)

使用標(biāo)準(zhǔn)格式來表示文本化的浮點數(shù):

julia> 1.0
1.0

julia> 1.
1.0

julia> 0.5
0.5

julia> .5
0.5

julia> -1.23
-1.23

julia> 1e10
1.0e10

julia> 2.5e-4
0.00025

上述結(jié)果均為 Float64 值。文本化的 Float32 值也可以直接輸入,這時使用 f 來替代 e

julia> 0.5f0
0.5f0

julia> typeof(ans)
Float32

julia> 2.5f-4
0.00025f0

浮點數(shù)也可以很容易地轉(zhuǎn)換為 Float32

julia> float32(-1.5)
-1.5f0

julia> typeof(ans)
Float32

十六進(jìn)制浮點數(shù)的類型,只能為 Float64

julia> 0x1p0
1.0

julia> 0x1.8p3
12.0

julia> 0x.4p-1
0.125

julia> typeof(ans)
Float64

Julia 也支持半精度浮點數(shù)(Float16) ,但只用來存儲。計算時,它們被轉(zhuǎn)換為 Float32

julia> sizeof(float16(4.))
2

julia> 2*float16(4.)
8.0f0

浮點數(shù)類型的零

浮點數(shù)類型中存在兩個零 ,正數(shù)的零和負(fù)數(shù)的零。它們相等,但有著不同的二進(jìn)制表示,可以使用 bits 函數(shù)看出:

julia> 0.0 == -0.0
true

julia> bits(0.0)
"0000000000000000000000000000000000000000000000000000000000000000"

julia> bits(-0.0)
"1000000000000000000000000000000000000000000000000000000000000000"

特殊的浮點數(shù)

有三個特殊的標(biāo)準(zhǔn)浮點數(shù):

特殊值 名稱 描述
Float16 Float32 Float64
Inf16 Inft32 Inf 正無窮 比所有的有限的浮點數(shù)都大
-Inf16 -Inft32 -Inf 負(fù)無窮 比所有的有限的浮點數(shù)都小
NaN16 NaN32 NaN 不存在 不能和任意浮點數(shù)比較大小(包括它自己)

詳見數(shù)值比較 。按照 IEEE 754 標(biāo)準(zhǔn) ,這幾個值可如下獲得:

julia> 1/Inf
0.0

julia> 1/0
Inf

julia> -5/0
-Inf

julia> 0.000001/0
Inf

julia> 0/0
NaN

julia> 500 + Inf
Inf

julia> 500 - Inf
-Inf

julia> Inf + Inf
Inf

julia> Inf - Inf
NaN

julia> Inf * Inf
Inf

julia> Inf / Inf
NaN

julia> 0 * Inf
NaN

typemintypemax 函數(shù)也適用于浮點數(shù)類型:

julia> (typemin(Float16),typemax(Float16))
(-Inf16,Inf16)

julia> (typemin(Float32),typemax(Float32))
(-Inf32,Inf32)

julia> (typemin(Float64),typemax(Float64))
(-Inf,Inf)

精度

大多數(shù)的實數(shù)并不能用浮點數(shù)精確表示,因此有必要知道兩個相鄰浮點數(shù)間的間距,也即計算機的精度

Julia 提供了 eps 函數(shù),可以用來檢查 1.0 和下一個可表示的浮點數(shù)之間的間距:

julia> eps(Float32)
1.1920929f-7

julia> eps(Float64)
2.220446049250313e-16

julia> eps() # same as eps(Float64)
2.220446049250313e-16

eps 函數(shù)也可以取浮點數(shù)作為參數(shù),給出這個值和下一個可表示的浮點數(shù)的絕對差,即,eps(x) 的結(jié)果與 x 同類型,且滿足 x + eps(x) 是下一個比 x 稍大的、可表示的浮點數(shù):

julia> eps(1.0)
2.220446049250313e-16

julia> eps(1000.)
1.1368683772161603e-13

julia> eps(1e-27)
1.793662034335766e-43

julia> eps(0.0)
5.0e-324

相鄰的兩個浮點數(shù)之間的距離并不是固定的,數(shù)值越小,間距越??;數(shù)值越大, 間距越大。換句話說,浮點數(shù)在 0 附近最稠密,隨著數(shù)值越來越大,數(shù)值越來越稀疏,數(shù)值間的距離呈指數(shù)增長。根據(jù)定義, eps(1.0)eps(Float64) 相同,因為 1.064 位浮點數(shù)。

函數(shù) nextfloatprevfloat 可以用來獲取下一個或上一個浮點數(shù):

julia> x = 1.25f0
1.25f0

julia> nextfloat(x)
1.2500001f0

julia> prevfloat(x)
1.2499999f0

julia> bits(prevfloat(x))
"00111111100111111111111111111111"

julia> bits(x)
"00111111101000000000000000000000"

julia> bits(nextfloat(x))
"00111111101000000000000000000001"

此例顯示了鄰接的浮點數(shù)和它們的二進(jìn)制整數(shù)的表示。

舍入模型

如果一個數(shù)沒有精確的浮點數(shù)表示,那就需要舍入了??梢愿鶕?jù) IEEE 754 標(biāo)準(zhǔn) 來更改舍入的模型:

julia> 1.1 + 0.1
1.2000000000000002

julia> with_rounding(Float64,RoundDown) do
       1.1 + 0.1
       end
1.2

默認(rèn)舍入模型為 RoundNearest ,它舍入到最近的可表示的值,這個被舍入的值使用盡量少的有效數(shù)字。

背景和參考資料

浮點數(shù)的算術(shù)運算同人們的預(yù)期存在著許多差異,特別是對不了解底層實現(xiàn)的人。許多科學(xué)計算的書籍都會詳細(xì)的解釋這些差異。下面是一些參考資料:

  • 關(guān)于浮點數(shù)算數(shù)運算最權(quán)威的指南是 IEEE 754-2008 標(biāo)準(zhǔn) ;然而,該指南沒有免費的網(wǎng)絡(luò)版
  • 一個簡短但是清晰地解釋了浮點數(shù)是怎么表示的, 請參考 John D. Cook 的文章 。它還簡述了由于浮點數(shù)的表示方法不同于理想的實數(shù)會帶來怎樣的問題
  • 推薦 Bruce Dawson 的關(guān)于浮點數(shù)的博客
  • David Goldberg 的每個計算機科學(xué)家都需要了解的浮點數(shù)算術(shù)計算,是一篇非常精彩的文章, 深入討論了浮點數(shù)和浮點數(shù)的精度問題
  • 更深入的文檔, 請參考“浮點數(shù)之父”William Kahan 的 collected writings ,其中詳細(xì)記錄了浮點數(shù)的歷史、理論依據(jù)、問題,還有其它很多的數(shù)值計算方面的內(nèi)容。更有興趣的可以讀 采訪浮點數(shù)之父

任意精度的算術(shù)

為保證整數(shù)和浮點數(shù)計算的精度,Julia 打包了 GNU Multiple Precision Arithmetic Library, GMP(https://gmplib.org/) 和 GNU MPFR Library。Julia 相應(yīng)提供了 BigIntBigFloat 類型。

可以通過基礎(chǔ)數(shù)值類型或 String 類型來構(gòu)造:

julia> BigInt(typemax(Int64)) + 1
9223372036854775808

julia> BigInt("123456789012345678901234567890") + 1
123456789012345678901234567891

julia> BigFloat("1.23456789012345678901")
1.234567890123456789010000000000000000000000000000000000000000000000000000000004e+00 with 256 bits of precision

julia> BigFloat(2.0^66) / 3
2.459565876494606882133333333333333333333333333333333333333333333333333333333344e+19 with 256 bits of precision

julia> factorial(BigInt(40))
815915283247897734345611269596115894272000000000

然而,基礎(chǔ)數(shù)據(jù)類型和 BigInt/BigFloat 不能自動進(jìn)行類型轉(zhuǎn)換,需要明確指定:

julia> x = typemin(Int64)
-9223372036854775808

julia> x = x - 1
9223372036854775807

julia> typeof(x)
Int64

julia> y = BigInt(typemin(Int64))
-9223372036854775808

julia> y = y - 1
-9223372036854775809

julia> typeof(y)
BigInt (constructor with 10 methods)

BigFloat 運算的默認(rèn)精度(有效數(shù)字的位數(shù))和舍入模型,是可以改的。然后,計算就都按照更改之后的設(shè)置來運行了:

julia> with_rounding(BigFloat,RoundUp) do
       BigFloat(1) + BigFloat("0.1")
       end
1.100000000000000000000000000000000000000000000000000000000000000000000000000003e+00 with 256 bits of precision

julia> with_rounding(BigFloat,RoundDown) do
       BigFloat(1) + BigFloat("0.1")
       end
1.099999999999999999999999999999999999999999999999999999999999999999999999999986e+00 with 256 bits of precision

julia> with_bigfloat_precision(40) do
       BigFloat(1) + BigFloat("0.1")
       end
1.1000000000004e+00 with 40 bits of precision

代數(shù)系數(shù)

Julia 允許在變量前緊跟著數(shù)值文本,來表示乘法。這有助于寫多項式表達(dá)式:

julia> x = 3
3

julia> 2x^2 - 3x + 1
10

julia> 1.5x^2 - .5x + 1
13.0

指數(shù)函數(shù)也更好看:

julia> 2^2x
64

數(shù)值文本系數(shù)同單目運算符一樣。因此 2^3x 被解析為 2^(3x) , 2x^3 被解析為 2*(x^3) 。

數(shù)值文本也可以作為括號表達(dá)式的因子:

julia> 2(x-1)^2 - 3(x-1) + 1
3

括號表達(dá)式可作為變量的因子:

julia> (x-1)x
6

不要接著寫兩個變量括號表達(dá)式,也不要把變量放在括號表達(dá)式之前。它們不能被用來指代乘法運算:

julia> (x-1)(x+1)
ERROR: type: apply: expected Function, got Int64

julia> x(x+1)
ERROR: type: apply: expected Function, got Int64

這兩個表達(dá)式都被解析為函數(shù)調(diào)用:任何非數(shù)值文本的表達(dá)式,如果后面跟著括號,代表調(diào)用函數(shù)來處理括號內(nèi)的數(shù)值(詳見函數(shù))。因此,由于左面的值不是函數(shù),這兩個例子都出錯了。

需要注意,代數(shù)因子和變量或括號表達(dá)式之間不能有空格。

語法沖突

文本因子與兩個數(shù)值表達(dá)式語法沖突: 十六進(jìn)制整數(shù)文本和浮點數(shù)文本的科學(xué)計數(shù)法:

  • 十六進(jìn)制整數(shù)文本表達(dá)式 0xff 可以被解析為數(shù)值文本 0 乘以變量 xff
  • 浮點數(shù)文本表達(dá)式 1e10 可以被解析為數(shù)值文本 1 乘以變量 e10 。E 格式也同樣。

這兩種情況下,我們都把表達(dá)式解析為數(shù)值文本:

  • 0x 開頭的表達(dá)式,都被解析為十六進(jìn)制文本
  • 以數(shù)字文本開頭,后面跟著 eE ,都被解析為浮點數(shù)文本

零和一

Julia 提供了一些函數(shù), 用以得到特定數(shù)據(jù)類型的零和一文本。

?
函數(shù) 說明
zero(x) 類型 x 或變量 x 的類型下的文本零
one(x)?類型x?或?變量x? 的類型下的文本一

這倆函數(shù)在數(shù)值比較中可用來避免額外的類型轉(zhuǎn)換

例如:

julia> zero(Float32)
0.0f0

julia> zero(1.0)
0.0

julia> one(Int32)
1

julia> one(BigFloat)
1e+00 with 256 bits of precision


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號