量化、資料類型、上溢和下溢

來源:互聯網
上載者:User

標籤:

之前在寫某個迭代演算法的時候,發現演算法在某些情況下會出錯,後來調試過程中發現,計算過程中,某些理論上大於0的數值會在迭代過程中變為0,最後計算過程中出現了除0,導致結果出錯。這篇文章的初始目的就是為了闡明為何某些理論上大於0的數在實際計算中會變為0(下溢),後來順便將很多人討論過資料類型轉換、運算精度也寫進去了。之前的有些部落格可能有一些局限性(局限於小數或是其他),這的確是一個不好闡述的話題,因此我從數字訊號處理中的量化出發,試圖給出一個較為直觀的認識。文章可能還有一些問題,還請批評指正。

1. 量化

    數字訊號處理中的量化指將輸入訊號從一個大的集合映射到一個的小集合的過程。可以簡單的、狹義的理解為將一個連續的量映射到離散的集合上的過程。如所示,紅色曲線是輸入訊號,通過3位元量化得到的結果為藍色曲線。

 

(By Hyacinth - Own work, CC BY-SA 3.0, https://commons.wikimedia.org/w/index.php?curid=30716342)

    自然的,可以引出三個問題

  1. 為何要將輸入訊號量化
  2. 量化對訊號本身有何影響
  3. 如何對輸入訊號進行量化

為何要將輸入訊號量化

    接收到的訊號,譬如通訊過程中的電磁波,一般將其視作類比量(時間上連續,取值連續),為了儲存、計算這些訊號,需要通過採樣、量化將其變為數字量。量化實際上是出於兩個考慮,其一是儲存、其二是計算。未經量化的訊號無法儲存在儲存空間中,同時也無法進行計算。

量化對訊號本身有何影響

    量化過程中,輸入訊號的集合往往是不可數的(或者集合有無窮元素),量化輸出訊號的集合是有限的。這也就意味著量化是一個無法復原的過程,這自然會對訊號有影響。如所示,量化過程會帶來量化雜訊(誤差,即量化前後訊號的差值),即量化後訊號會有失真,沒有額外先驗知識的情況下,失真是無法恢複的。

By Gregory Maxwell - http://wiki.xiph.org/File:Dsat_011.png, CC BY 3.0, https://commons.wikimedia.org/w/index.php?curid=26171868

如何對輸入訊號進行量化 (註:此處僅討論標量量化)

    上面的兩幅圖中,量化是通過將輸入範圍劃分為若干個地區,對於落入同一地區內的訊號賦值為同一個(二進位)數。地區的劃分是均勻的,這一量化關係可以表示為。

    不同輸入訊號取值下,量化誤差是相同的,這種方式被稱為均勻量化。但是很多情況下,我們更關注相對的量化誤差(量化誤差/訊號取值),即對於小訊號而言,量化誤差較小,而大訊號可以具有相對較大的量化誤差。這一情況下可以採用不同的量化方式,如所示(註:這是我瞎編的,有對應的非均勻量化的標準)。

    非均勻量化可以獲得更高的信噪比,兩種不同的量化方式具有不同的應用。除此之外還有其他量化方式,此處不再說明。

2. 資料類型

    儘管上節討論的是數字訊號處理中的量化,但是量化、或是類似量化的操作實際上出現在很多地方。譬如電腦的儲存空間是有限的,32位元的儲存空間僅僅只能夠表示種不同的可能。然而很多情況下,我們所期待的運算是在實數域上進行的,而類似數字訊號處理中的情況,電腦只能對量化後的訊號進行儲存和計算。

2.1 資料類型和量化

    資料的儲存,設計到資料類型,這裡討論兩種:整型(integer)和浮點型 (float)。此處,類似量化的思路,我們認為電腦將實數域上的輸入,量化為整型/浮點型進行表示。

整型(考慮32位元有符號整型)

    輸入實數域數值,量化範圍為,量化方式為均勻量化,假設為量化結果,則有

    譬如,,則取。對不同的,量化誤差是一個恒定的取值。

浮點型(32位元浮點)

    浮點和整型比稍微複雜一些,參考維基百科, 32位元浮點數的儲存方式表示如。

    對應浮點數取值可表示為(十進位)

    大於0的浮點數依次為,然而大於1的浮點數依次為,即量化間隔是不同的,實際上,量化精度和資料大小的關係可表示為

    即將一個實數域上的數儲存為浮點表示,可以看作是一個非均勻量化的過程。

注1:本節中的量化,實際上應該是量化和編碼兩個過程,不僅僅將數值量化了,同時採用相應的編碼方式編碼儲存。

注2:資料類型的定義比本文描述要複雜,因為設計到0,無窮和非數的處理。

注3:不同運行環境,對於float的定義不盡相同。

2.2 出錯的計算式

    類似下面的代碼在部落格園討論過很多次了,即

float a = (float) 10.375;float b = (float) 2.263;System.out.println(a+b);

    這一代碼在我的機器上運行結果輸出為12.6380005。雖然鮮有人討論關於(int) 10.375+ (int) 2.263 = 12這個式子,但是無論是整型還是浮點類型,出現這個問題的緣由都是一樣的——我們任意在實數域(或是有理數域)選擇了兩個數,然而電腦中儲存的是量化之後的結果,無論對integer或是float都是這樣。只是我們習慣性的認為float強大到無所不能,但是它的表示能力依舊是有限的。

    第一節中討論了量化前後訊號的變化,會帶來量化雜訊。同理,我們給出的數,譬如10.375和2.263,利用浮點儲存同樣會帶來雜訊。而計算結果和理論值的差距就是這個雜訊的直接體現。

    我們並不能夠保證,因此計算看似出錯了,實際上只是電腦按自己邏輯計算出現的誤差。

2.3 資料類型的轉換

    類似float→double,或是int→long此類的類型轉換,或是量化區間增大了,或是量化精度提升了,轉化過程不會引發任何問題,簡單舉例()。類似這樣的量化關係,從int→long→int,或是float→double→float,轉化不會進一步引入雜訊。

    然而如下的轉化則不然,即int→float→int

int a = 200000002;float b = (float) a;int c = (int)b;System.out.println(c);

    輸出結果為200000000;轉換過程的可表示為

3. 上溢和下溢

    上溢(Arithmetic overflow),即運算結果超出了寄存器或儲存空間所能儲存或表示的範圍。從量化的角度來看,可以認為是超過了量化範圍,上溢一般很容易被發現,但有時也會被忽略。譬如,leetcode的第一題,一個有一些問題的代碼也能夠通過測試

Given an array of integers, return indices of the two numbers such that they add up to a specific target.

public int[] twoSum(int[] nums, int target) {    for (int i = 0; i < nums.length; i++) {        for (int j = i + 1; j < nums.length; j++) {            if (nums[j] == target - nums[i]) {                return new int[] { i, j };            }        }    }    throw new IllegalArgumentException("No two sum solution");}

    上面的代碼是提供的解答方式,但是由於nums是int類型的,target也是int類型的,因此target-nums[i]可能會overflow,導致出現錯誤的結果。

    相對而言,“下溢”就隱蔽很多了,下溢(Arithmetic underflow)很難發現,也很不好處理。這裡的underflow不是指資料小於所能表示的最小值,這種情況,譬如-129不再int8的表示範圍,應該被歸類到overflow,即“運算結果超出了寄存器或儲存空間所能儲存或表示的範圍”。

    浮點數設計過程中,資料越大,量化精度越低,然而有一個例外,即0附近。32位元浮點數,和0最近的正常數為(不同標準不同),然而比最接近的數為。這意味著0附近的量化精度是相對較低的,相對較低的問題並不會帶來過多的問題,但是一旦一個非0的資料由於足夠小,被儲存為0,則可能會帶來一系列問題。本來我想舉個例子,但是Java裡有點怪怪的,我也沒弄明白

float a = (float) (1.5*java.lang.Math.pow(10,-45));float b = Float.MIN_NORMAL;System.out.println(b>a);System.out.println(a);System.out.println(b);

    這裡我定義了一個a和一個b,b是float中的最小的正常數,然而顯然比b小,同時a也大於0,不知道這時怎麼處理的。暫時沒有查相關資料。

    但是不管怎麼說,只要一個數足夠小,就會被下溢為0,而在迭代演算法中,這種情況很有可能會發生。如果不幸這個數被作為了除數,那麼就會出現除0的情況,引發錯誤 。

4. 其他

    值得關注的問題是,談論了那麼多關於量化雜訊的問題,那麼,電腦的計算結果還靠譜嗎?即

電腦的計算結果是否能保證絕對的準確性?

    在一定條件下是可以的。回到第一節、第二節會發現討論的前提是

  •     輸入訊號的集合大於量化輸出訊號的集合(譬如輸入訊號是類比的,輸出是數位),量化過程會引入量化誤差。
  •     如果期望的運算是在實數域上進行,那麼資料按資料類型儲存的過程可以看作是量化編碼的過程。

    數字訊號處理領域,接收訊號是類比的,需要通過ADC採樣量化,這時量化雜訊是必然存在的。然而,電腦中的資料可能具有不同的含義。譬如,採用變數a表示書本的頁數。那麼,書本的頁數必然是一個不小於0的整數,且一般而言會是有限的。那麼,此時若a採用整型儲存,就能夠精確的表示書本的頁數,不引入任何誤差。

    由此出發,對於不同的應用,如果有一些先驗知識,我們有可能可以設計不同的資料類型/結構,以及相應的計算方法,得到準確的計算結果。

量化、資料類型、上溢和下溢

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.