Julia 整數(shù)和浮點(diǎn)數(shù)

2022-02-25 15:45 更新

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

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

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

  • 整數(shù)類型

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

浮點(diǎn)數(shù)類型:

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

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

整數(shù)

使用標(biāo)準(zhǔn)方式來(lái)表示文本化的整數(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)原生的有符號(hào)和無(wú)符號(hào)整數(shù)類型的別名:

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

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

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

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

無(wú)符號(hào)整數(shù)的輸入和輸出使用前綴 0x 和十六進(jìn)制數(shù)字 0-9a-f (也可以使用 A-F )。無(wú)符號(hào)數(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 中,如果計(jì)算結(jié)果超出數(shù)據(jù)類型所能代表的最大值,將會(huì)發(fā)生溢出:

julia> x = typemax(Int64)
9223372036854775807

julia> x + 1
-9223372036854775808

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

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

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

除法錯(cuò)誤

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

浮點(diǎn)數(shù)

使用標(biāo)準(zhǔn)格式來(lái)表示文本化的浮點(diǎ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 值也可以直接輸入,這時(shí)使用 f 來(lái)替代 e

julia> 0.5f0
0.5f0

julia> typeof(ans)
Float32

julia> 2.5f-4
0.00025f0

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

julia> float32(-1.5)
-1.5f0

julia> typeof(ans)
Float32

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

julia> 0x1p0
1.0

julia> 0x1.8p3
12.0

julia> 0x.4p-1
0.125

julia> typeof(ans)
Float64

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

julia> sizeof(float16(4.))
2

julia> 2*float16(4.)
8.0f0

浮點(diǎn)數(shù)類型的零

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

julia> 0.0 == -0.0
true

julia> bits(0.0)
"0000000000000000000000000000000000000000000000000000000000000000"

julia> bits(-0.0)
"1000000000000000000000000000000000000000000000000000000000000000"

特殊的浮點(diǎn)數(shù)

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

特殊值 名稱 描述
Float16 Float32 Float64
Inf16 Inft32 Inf 正無(wú)窮 比所有的有限的浮點(diǎn)數(shù)都大
-Inf16 -Inft32 -Inf 負(fù)無(wú)窮 比所有的有限的浮點(diǎn)數(shù)都小
NaN16 NaN32 NaN 不存在 不能和任意浮點(diǎn)數(shù)比較大?。òㄋ约海?/td>

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

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ù)也適用于浮點(diǎn)數(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ù)并不能用浮點(diǎn)數(shù)精確表示,因此有必要知道兩個(gè)相鄰浮點(diǎn)數(shù)間的間距,也即計(jì)算機(jī)的精度。

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

julia> eps(Float32)
1.1920929f-7

julia> eps(Float64)
2.220446049250313e-16

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

eps 函數(shù)也可以取浮點(diǎn)數(shù)作為參數(shù),給出這個(gè)值和下一個(gè)可表示的浮點(diǎn)數(shù)的絕對(duì)差,即,eps(x) 的結(jié)果與 x 同類型,且滿足 x + eps(x) 是下一個(gè)比 x 稍大的、可表示的浮點(diǎn)數(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

相鄰的兩個(gè)浮點(diǎn)數(shù)之間的距離并不是固定的,數(shù)值越小,間距越?。粩?shù)值越大, 間距越大。換句話說(shuō),浮點(diǎn)數(shù)在 0 附近最稠密,隨著數(shù)值越來(lái)越大,數(shù)值越來(lái)越稀疏,數(shù)值間的距離呈指數(shù)增長(zhǎng)。根據(jù)定義, eps(1.0)eps(Float64) 相同,因?yàn)?1.064 位浮點(diǎn)數(shù)。

函數(shù) nextfloatprevfloat 可以用來(lái)獲取下一個(gè)或上一個(gè)浮點(diǎn)數(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"

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

舍入模型

如果一個(gè)數(shù)沒有精確的浮點(diǎn)數(shù)表示,那就需要舍入了。可以根據(jù) IEEE 754 標(biāo)準(zhǔn) 來(lái)更改舍入的模型:

julia> 1.1 + 0.1
1.2000000000000002

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

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

背景和參考資料

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

任意精度的算術(shù)

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

可以通過(guò)基礎(chǔ)數(shù)值類型或 String 類型來(lái)構(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 不能自動(dòng)進(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 運(yùn)算的默認(rèn)精度(有效數(shù)字的位數(shù))和舍入模型,是可以改的。然后,計(jì)算就都按照更改之后的設(shè)置來(lái)運(yùn)行了:

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ù)值文本,來(lái)表示乘法。這有助于寫多項(xiàng)式表達(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ù)同單目運(yùn)算符一樣。因此 2^3x 被解析為 2^(3x)2x^3 被解析為 2*(x^3) 。

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

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

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

julia> (x-1)x
6

不要接著寫兩個(gè)變量括號(hào)表達(dá)式,也不要把變量放在括號(hào)表達(dá)式之前。它們不能被用來(lái)指代乘法運(yùn)算:

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

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

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

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

語(yǔ)法沖突

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

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

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

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

零和一

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

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

這倆函數(shù)在數(shù)值比較中可用來(lái)避免額外的類型轉(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)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)