最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

Fortran中的數(shù)字精度的探究

2021-12-15 23:53 作者:汗族小子  | 我要投稿

近期自己摸索了一些Fortran其中遇到了一些問(wèn)題,因此順便就去整理了一些資料,與大家分享。 ----------(hzxz 2021.12.15)

一.Fortran中的數(shù)字類型

Fortran中的數(shù)字類型分為整數(shù)(Integer),實(shí)數(shù)(Real)和復(fù)數(shù)(Complex)三種類型。復(fù)數(shù)類型由實(shí)部和虛部的兩個(gè)實(shí)數(shù)組成,這里我們不多討論。

通常能夠在兩種情況下見(jiàn)到數(shù)字,其一是標(biāo)定一變量的類型,Integer 、Real 和Complex 均用于定義其所示類型的變量;其二則是直接作為數(shù)字常量出現(xiàn),如 12、12.008、1.2E5 ,這種方式在C++中被稱之為字面值常量。


1.整數(shù)類型

通常在Fortran中所指的整數(shù)類型都是具有符號(hào)的,可以等同于C++中的int類型,默認(rèn)情況下寫(xiě)出的整型數(shù)字也是這個(gè)類型。無(wú)符號(hào)數(shù)作為一種新的數(shù)據(jù)類型在F95開(kāi)始被引入,為 UNSIGNED 類型,不在本文的討論范圍內(nèi)。有興趣的同學(xué)可以參考[鏈接](https://docs.oracle.com/cd/E19205-01/819-5263/aevnb/index.html).

1.1 整型變量

使用Integer定義整型變量,和C++的int類型相同用于表示整數(shù)類型。在默認(rèn)的情況下,其定義的數(shù)據(jù)長(zhǎng)度為4字節(jié)。在需要的情況下,我們也可以人為指定其數(shù)據(jù)長(zhǎng)度以增加其儲(chǔ)存上限。


1.2 整型數(shù)字


整形數(shù)字常數(shù)直接出現(xiàn)在源碼中,其也存在默認(rèn)的長(zhǎng)度,默認(rèn)長(zhǎng)度和整型變量一樣為4字節(jié)。如果給出的數(shù)字超出默認(rèn)的長(zhǎng)度,則會(huì)出現(xiàn)截?cái)啵@在使用中是無(wú)意義的,因此編譯器和IDE會(huì)報(bào)錯(cuò)。

通過(guò)添加編譯參數(shù) -fno-range-check 可以阻止編譯器進(jìn)行整數(shù)的上限檢查,但是運(yùn)行后的結(jié)果如下,這在實(shí)際計(jì)算中被視作錯(cuò)誤的結(jié)果。


1.3 整型的表示范圍

INTEGER類型根據(jù)其類型長(zhǎng)度不同具有不同的數(shù)據(jù)表示范圍,在Fortran中我們可以使用內(nèi)置的huge函數(shù)得到某一整數(shù)的表示范圍上限,即能表達(dá)的最大的數(shù)。

實(shí)際上,整數(shù)(INTEGER類型)的表示范圍和其所占字節(jié)數(shù)的關(guān)系如下,令k為所占字節(jié)數(shù):

%5B-2%5E%7B8k-1%7D%2C2%5E%7B8k-1%7D-1%5D

1.4 人為指定整型變量和數(shù)據(jù)的空間大小

實(shí)際使用中,我們可以根據(jù)自身需求來(lái)靈活調(diào)整整形數(shù)據(jù)的大小,F(xiàn)ortran90之后可以通過(guò)設(shè)定種別(KIND)來(lái)修改變量的空間占用大小。對(duì)于Fortran中的整型數(shù)字常量,我們也可以在其后顯式追加KIND后綴來(lái)人為指定kind數(shù)目,即直接加下劃線再加KIND值。在下面的代碼中我們將整數(shù)類型的變量聲明為不同KIND的數(shù)目,對(duì)整型常數(shù)也給定種別,然后可以觀察他們的表示范圍上限。

預(yù)期的結(jié)果為:

關(guān)于FORTRAN-KIND,也請(qǐng)[參考](https://gcc.gnu.org/onlinedocs/gcc-3.4.6/g77/Kind-Notation.html)。

2.實(shí)數(shù)類型(浮點(diǎn)數(shù)類型)

在Fortran中,實(shí)數(shù)類型作為浮點(diǎn)數(shù)儲(chǔ)存,和C++中的浮點(diǎn)數(shù)(float和double)類似。 ? ?// [reference](https://docs.oracle.com/cd/E19957-01/805-4939/6j4m0vn8i/index.html)


2.1 浮點(diǎn)類型的表示方法

和C++相同,F(xiàn)ortran也使用業(yè)界統(tǒng)一的 [IEEE-754標(biāo)準(zhǔn)](https://people.eecs.berkeley.edu/~wkahan/ieee754status/IEEE754.PDF),微軟官方的C++文檔也有相關(guān)可參考[描述](https://docs.microsoft.com/zh-cn/cpp/build/ieee-floating-point-representation?view=msvc-170)。通常根據(jù)所占據(jù)的字節(jié)數(shù)不同,可以分為單精度浮點(diǎn)數(shù)Single(在Fortran為REAL*4,C/C++中的float)、雙精度浮點(diǎn)數(shù)Double(在Fortran中為REAL*8,C/C++中的double)。另外還有半精度(2字節(jié))、四元精度(16字節(jié))和雙擴(kuò)展精度浮點(diǎn)數(shù)Double-Extended(10 字節(jié)),這些格式作為可選實(shí)現(xiàn),在某些編譯器和某些語(yǔ)言中被實(shí)現(xiàn)為數(shù)據(jù)類型,不做過(guò)多討論。

其中單精度浮點(diǎn)數(shù)使用四字節(jié)儲(chǔ)存,即32位,其中包含一位符號(hào)位,8位指數(shù)位,23位有效數(shù)位;雙精度浮點(diǎn)數(shù)使用八字節(jié)儲(chǔ)存,即64位,其中包含一位符號(hào)位,11位指數(shù)位,52位有效數(shù)位。

詳細(xì)的浮點(diǎn)數(shù)表示方式可以參考以上的參考文檔,或者實(shí)機(jī)測(cè)試。


2.2 浮點(diǎn)數(shù)變量

對(duì)于雙精度來(lái)說(shuō),早期 Fortran 提供了 Double precision 關(guān)鍵字來(lái)定義它。就新語(yǔ)法來(lái)說(shuō),我們不再建議使用這個(gè)關(guān)鍵字。而統(tǒng)一使用REAL類型和 Kind 進(jìn)行定義。例如:


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

同樣的,在代碼中直接出現(xiàn)的字面值形式的實(shí)數(shù)數(shù)字,即被視作浮點(diǎn)數(shù)常數(shù),例如“3.1415926535”等,在默認(rèn)情況下,F(xiàn)ortran將其的精度視作單精度,換言之,在代碼中直接出現(xiàn)的數(shù)字,在被編譯器接受并儲(chǔ)存的時(shí)候會(huì)被作為單精度數(shù)據(jù)儲(chǔ)存為常數(shù)。下面的示例代碼中可以看出來(lái)這一點(diǎn)。

在默認(rèn)gfortran下,程序運(yùn)行的預(yù)期的結(jié)果如下,第二個(gè)數(shù)據(jù)為默認(rèn)浮點(diǎn)常數(shù)輸出,第三個(gè)為人為限定kind=8??梢钥吹角皟蓚€(gè)數(shù)字輸出都出現(xiàn)了精度損失,但第一個(gè)的輸出位數(shù)確能達(dá)到KIND=8的要求。

對(duì)比三個(gè)數(shù)字的輸出可以發(fā)現(xiàn),其實(shí)第一個(gè)數(shù)字和第二個(gè)數(shù)字一樣,都是在解析浮點(diǎn)常數(shù)時(shí)出現(xiàn)的精度丟失的。在這個(gè)過(guò)程中,雖然賦值操作和輸出操作支持的精度為雙精度(KIND=8),但由于浮點(diǎn)常數(shù)從代碼源文件進(jìn)入內(nèi)存時(shí)即只有單精度,實(shí)際的整個(gè)操作下來(lái)有效精度只有單精度(KIND=4),這才導(dǎo)致我們看到精度損失。因此如果對(duì)賦值操作有精度需求,需要對(duì)等號(hào)左右人為給定合適的KIND。


二.常用的種別函數(shù)介紹

在FORTRAN90以后,提供了一些內(nèi)部函數(shù)進(jìn)行種別KIND相關(guān)的操作。


KIND(X):函數(shù)KIND用于查詢變量的種別,它返回X的種別值,X可以為變量和常量均可。如:KIND(0)返回值是整型的標(biāo)準(zhǔn)種別值,KIND(0.)、KIND(.FALSE.)、 KIND(“A”)分別返回實(shí)型、邏輯型、字符型的標(biāo)準(zhǔn)種別值。

SELECTED_REAL_KIND([n],[m]):該函數(shù)返回實(shí)型變量(浮點(diǎn)數(shù)變量)對(duì)所取的值范圍和精度恰當(dāng)?shù)姆N別值。其中n是指明十進(jìn)制有效位的位數(shù),m指明值范圍內(nèi)以10為底的冪次。例如: SELECTED_REAL_KIND(6,70)的返回值為8,表示一個(gè)能表達(dá)6位精度、值范圍在-1070—+1070之間實(shí)型數(shù)的種別值為8。硬件不滿足時(shí)會(huì)得到異常返回值:-1(當(dāng)精度位數(shù)達(dá)不到時(shí)),-2(當(dāng)數(shù)值范圍達(dá)不到時(shí)),-3(兩者都達(dá)不到時(shí))。


對(duì)于浮點(diǎn)數(shù)X,它的精度和范圍也可通過(guò)內(nèi)部函數(shù)PRECISION(X)和RANGE(X)查出。


SELECTED_INT_KIND([m]):該函數(shù)返回整型變量對(duì)所取的值范圍恰當(dāng)?shù)姆N別值。m同樣為以10為底數(shù)的冪次。


通常我們推薦對(duì)變量和常數(shù)做適當(dāng)?shù)腒IND限定,尤其是對(duì)于需要高精度的數(shù)據(jù),應(yīng)該給定必要的KIND限制,以免出現(xiàn)不必要的精度損失?;谝陨系姆N別函數(shù),我們可以更好的指定KIND,通常為了保持程序的跨平臺(tái)性能,可以將KIND作為參數(shù)給定便于修改。


三.通過(guò)編譯器參數(shù)控制數(shù)據(jù)長(zhǎng)度


實(shí)際使用中,不同的硬件設(shè)備和不同的編譯環(huán)境,可能具有不同的數(shù)據(jù)長(zhǎng)度(KIND)的默認(rèn)值,或者存在某種需求,需要修改代碼中未顯式聲明種別的數(shù)據(jù),則可以通過(guò)編譯器參數(shù)來(lái)進(jìn)行修改。

1.調(diào)整默認(rèn)數(shù)據(jù)長(zhǎng)度


在GNU的gfortran中,可以使用如下的參數(shù)對(duì)數(shù)據(jù)進(jìn)行控制。


  • -fno-range-check

? ? 此參數(shù)會(huì)禁止編譯器對(duì)編譯中的常數(shù)表達(dá)式的范圍進(jìn)行檢查。例如遇到$\frac{1}{0}$時(shí),如果不進(jìn)行檢查將會(huì)對(duì)結(jié)果賦值為+Infinity,對(duì)于超過(guò)HUGE的常數(shù)表達(dá)式也不會(huì)進(jìn)行錯(cuò)誤提示,而是直接進(jìn)行溢出處理,例如代碼 `write(*,*) -129_1`將輸出127.

  • -fdefault-integer-8

? ? 此參數(shù)將設(shè)置默認(rèn)的整型數(shù)據(jù)INTEGER和邏輯型數(shù)據(jù)為8字節(jié)的寬度,對(duì)于沒(méi)有人為限定KIND的整數(shù)常數(shù)也生效,但是不會(huì)對(duì)已經(jīng)有KIND限定的整型變量和數(shù)據(jù)生效。

  • -fdefault-real-8

? ? 此參數(shù)將會(huì)把浮點(diǎn)數(shù)的默認(rèn)數(shù)據(jù)占用設(shè)定為8字節(jié)。對(duì)于沒(méi)有人為限定的浮點(diǎn)數(shù)常數(shù)也生效。但是,這個(gè)參數(shù)也會(huì)將FORTRAN的DOUBLE PRECISION 類型定義為16字節(jié)(在舊的FORTRAN中可以通過(guò)此類型來(lái)聲明雙精度浮點(diǎn))。除非同時(shí)使用-fdefault-double-8 參數(shù)。本參數(shù)不對(duì)已經(jīng)有KIND限定的數(shù)據(jù)生效。

  • -fdefault-double-8

? ? 此參數(shù)會(huì)將FORTRAN中的DOUBLE PRECISION 的默認(rèn)類型設(shè)置為8字節(jié),由于通常我們以REAL來(lái)聲明,因此使用到此DOUBLE PRECISION的情況多出現(xiàn)在老舊的代碼中,建議更換為REAL并使用kind限定以達(dá)到表示雙精度浮點(diǎn)數(shù)的目的。此參數(shù)可以配合-fdefault-real-8參數(shù)使用以阻止DOUBLE PRECISION類型的寬度提升。當(dāng)然,對(duì)已經(jīng)限定種別的數(shù)據(jù)此參數(shù)亦不生效。


關(guān)于以上的參數(shù)有一個(gè)很危險(xiǎn)的場(chǎng)景:

以上代碼使用 gfortran 默認(rèn)參數(shù)可以直接編譯,只是由于浮點(diǎn)數(shù)常數(shù)的默認(rèn)KIND為4,因此在賦值給變量a的時(shí)候會(huì)出現(xiàn)精度損失,這個(gè)在上文已經(jīng)提到,通常我們通過(guò)人為限定種別的情況下來(lái)避免精度損失。但是對(duì)于既有的代碼直接修改可能比較繁瑣,可以嘗試使用參數(shù) -fdefault-real-8 對(duì)無(wú)種別限制的浮點(diǎn)數(shù)指定KIND。但實(shí)際編譯中,如果添加參數(shù)-fdefault-real-8 則會(huì)出現(xiàn)以下的報(bào)錯(cuò)。

這個(gè)問(wèn)題咋一看非常不合常理,針對(duì)double類型特化的函數(shù)dsign為什么對(duì)a的類型不能接受?但是經(jīng)過(guò)試驗(yàn)之后才發(fā)現(xiàn),其實(shí)dsign所謂的針對(duì)double其實(shí)是針對(duì)的Fortran內(nèi)置的DOUBLE PRECISION類型,而不是固定C++的double或者IEEE的雙精度浮點(diǎn)數(shù)(double),因此這個(gè)時(shí)候dsign所需要的參數(shù)的類型為DOUBLE PRECISION類型,亦或者使用REAL(KIND=16)的數(shù)據(jù)也能夠滿足要求。

因此,針對(duì)以上的情況,如果確實(shí)需要使用-fdefault-real-8 進(jìn)行浮點(diǎn)數(shù)的默認(rèn)種別的指定,那么搭配參數(shù)-fdefault-double-8 可以使得dsign函數(shù)能夠如原預(yù)期一樣運(yùn)行。當(dāng)然,也可以使用其他的方法完成所需的目的。


從以上的情況,我們也能夠得到經(jīng)驗(yàn),在編碼過(guò)程中,為保證程序的正確性和安全性,對(duì)于有特定精度需求的數(shù)據(jù),應(yīng)該盡量人為給定種別,除非你能夠接受其被編譯器自動(dòng)限定為某些規(guī)定中的種別。對(duì)于內(nèi)置的函數(shù),除非確定自己所需的類型,否則應(yīng)盡量使用通用類型的函數(shù)。


2.強(qiáng)制調(diào)整數(shù)據(jù)長(zhǎng)度


gfortran也提供了一些參數(shù)用于強(qiáng)行修改特定類型的kind,在某些極其特定的情況下會(huì)被使用,通常不需要在意,如:


  • -finteger-4-integer-8 此參數(shù)將強(qiáng)行將代碼中的所有INTEGER(KIND=4)的變量強(qiáng)行轉(zhuǎn)化為INTEGER(KIND=8),如果轉(zhuǎn)換失敗則報(bào)錯(cuò)。

  • -freal-4-real-8

  • -freal-4-real-10

  • ?-freal-4-real-16

  • -freal-8-real-4

  • -freal-8-real-10

  • -freal-8-real-16

更多的參數(shù)請(qǐng)參考GFortran編譯器的說(shuō)明[文檔](https://gcc.gnu.org/onlinedocs/gcc-5.1.0/gfortran/Fortran-Dialect-Options.html#Fortran-Dialect-Options)。


Reference:

[oracle對(duì)usigned整數(shù)的介紹](https://docs.oracle.com/cd/E19205-01/819-5263/aevnb/index.html)

[oracle對(duì)于Fortran浮點(diǎn)數(shù)的介紹](https://docs.oracle.com/cd/E19957-01/805-4939/6j4m0vn8i/index.html)

[IEEE-754 浮點(diǎn)數(shù)標(biāo)準(zhǔn)](https://people.eecs.berkeley.edu/~wkahan/ieee754status/IEEE754.PDF),

[微軟官方的C++文檔的浮點(diǎn)數(shù)介紹](https://docs.microsoft.com/zh-cn/cpp/build/ieee-floating-point-representation?view=msvc-170)

[gfortran中對(duì)KIND的說(shuō)明](https://gcc.gnu.org/onlinedocs/gcc-3.4.6/g77/Kind-Notation.html)

[GNU-gfortran-文檔](https://gcc.gnu.org/onlinedocs/gcc-5.1.0/gfortran/Fortran-Dialect-Options.html#Fortran-Dialect-Options)


Fortran中的數(shù)字精度的探究的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國(guó)家法律
柘城县| 远安县| 双江| 资阳市| 南通市| 察隅县| 秭归县| 巍山| 方山县| 潢川县| 疏勒县| 元氏县| 扬中市| 方城县| 枣强县| 宁河县| 永清县| 阳泉市| 托克托县| 静安区| 梨树县| 常山县| 萝北县| 辽中县| 汾阳市| 金湖县| 柳林县| 兰西县| 望都县| 南郑县| 思南县| 长汀县| 汉沽区| 罗甸县| 公安县| 沈丘县| 水富县| 滨海县| 灵寿县| 西贡区| 临朐县|