C語言 浮點數(floating point)

更新於 發佈於 閱讀時間約 11 分鐘

分類

  浮點數其實就像是小數一樣,該變數會將取得的小數值轉變為二進位儲存,分為三種類型:

△單精度浮點數、單精度浮點值(float)

4bytes能表達的小數類型,範圍在±3.4e-38~±3.4e+38之間,而有效位數為前7位,但能絕對保證的只有前6位數字。看不懂e是什麼嗎?點我!

△雙精度浮點數、雙精度浮點值(double)

8bytes能表達的小數類型,範圍在±1.79E-308 ~ ±1.79E+308之間,而精確位數前16位,但絕對保證的只有前15位數字。

長雙精度浮點數、長雙精度浮點值(long double)

16bytes能表達的小數類型,範圍在±1.79E-308 ~ ±1.79E+308之間,與double相同,但是精確位數則是前19位,而絕對保證的只有前18位數字。
#include "stdio.h"
#define __USE_MINGW_ANSI_STDIO 1

int main(void){
  float h = 0.5;//單精度浮點數宣告
  printf("%f\n",h);//%f 代表float

  double i = 0.5;//雙精度浮點數宣告
  printf("%lf\n",i);//%lf 代表double

  long double j = 1.5;//長雙精度浮點數宣告
  printf("%Lf\n",j);//%Lf 代表long double
}
--------------------------------結果---------------------------------
0.500000
0.500000
1.500000

有效位數是什麼?

儲存形式

  在理解有效位數之前,我們先來講講浮點數的儲存方式吧。浮點數的所占bits會用來分給號(sign)、指數(exponent)、尾數(mantissa),以float的32bits為例:
●號(sign):佔1bit,用於表示其浮點數的正負,0表示正數,反之1代表負數。
●指數(exponent):佔8bits,用於表示儲存的移位關係。在電腦中指數的儲存方式是以指數偏移量為0,因此會等於移位數 + 指數偏移量。指數偏移量 = 2 ^ (k - 1) - 1,其中k為指數(exponent)所占用的bits數,因此float的指數偏移量 = 2 ^ (8 - 1) - 1 = 2 ^ 7 - 1 = 127。
●尾數(mantissa):佔23bits,用於表示小數的二進位。
浮點數(floating point) = 號(sign)*尾數(mantissa)*2^指數(exponent)
floating point = S * M *2 ^ E
其中 號(sign)為±1,而 2^指數(exponent)代表2的e次方。
  很難懂嗎?我們來以1.25作為例子好了。
1、將7.25化為二進位
  111.01
2、確認整個小數是為正數還是負數,倘若是正數則 號(sign)為0,反之負數則為1。
  S:0
3、將小數點移到能讓整個小數最高位是個位數的位置
  1.1101
4、找到由左而右的第一個1,只取後面的數字。
  1101
  捨去第一個1的原因在於,假設有一個10進位的數字是0100,我們會很自然地把前面的
0刪掉只留下100,因為那個0是無意義的。化做二進位來說,捨去掉無意義的0之後,無論
如何最前方就一定是1了,因此不必特意儲存也會知道。
5、將這串數字,後面補上數個0,直到共有23位,而這就是尾數(mantissa)。
  M:1101 0000 0000 0000 0000 000
6、計算剛剛第2點中小數點移了幾位,往左+1,往右-1,這則是指數(exponent)。
  111.01 → 1.1101 小數點共往左移動了兩格所以是2。
  但還沒結束喔,還要再加上指數偏移數也就是127。
  
  2 + 127 = 129,化做二進位表示為
  E:1000 0001
7、最終整個儲存形式為:
  0   1000 0001   1101 0000 0000 0000 0000 000
  S       E                     M
8、計算方式
  S = +1
  E = 129 - 127 =2
  M = 0.1101(二進位) + 1(被捨去的) = 0.5 + 0.25 + 0.0625 + 1
  = 0.8125 + 1 = 1.8125
  floating point = S * M * 2 ^ e
  floating point = +1 * 1.8125 * 2 ^ 2
           = 1.8125 * 4 = 7.25
  

不精確的原因

  由float儲存方式我們可以知道儲存空間的有限,再者是二進位小數的難點。以一個簡單的例子即可知道,0.3的二進位為0.01001100110011001100,事實上這只是一部分,換句話說,它就是一個無限小數。
  設x為基數,y為進位制,z為該位數的話,可以看出小數其實就是 x y ^z。以十進位的0.6為例,就是 6 * 10 ^ -1。
  但在二進位當中值只會有0或1,因此小數的部分可以簡化為,是由數個2 ^ z組成,其中z為負數。但像剛剛舉例的0.3就無法用二進位完整表示,只能用無限個二進位小數做到逼近的值。
  這時候就出現了一個問題,剛剛有說儲存空間的有限,我們可以知道只能用有限的二進位是難以表達出像0.3的這種數字,因此一定多少都會有誤差,這就是為什麼浮點數會有不精確的問題。

範圍與有效位數的差別

  為什麼float的範圍可以這麼大?在剛剛的儲存形式當中,指數的形式可以有效幫助浮點數擴大範圍。
如二進位0.0........01,假設小數點後方的0有125個。稍微計算過後我們可以知道儲存
形式為:
  0   0000 0001   0000 0000 0000 0000 0000 000
  S E M

計算方式:
S = + 1
E = -126
M = 1
  因此這種極小的小數,都能因為指數而正確儲存。那有效位數的存在其實就是剛剛有提到的,因為二進位小數儲存的難度,導致數值不精確。而有效位數則是這個儲存空間能夠正確儲存的範圍,當然有效位數當中還是有少部分小數會是錯誤,因此精確位數的存在則是為了表示該範圍內的數值絕對是完全精確的。

浮點數不被建議使用的原因

精確問題

  在一個專案當中,數字的精確是非常重要的,或許你會覺得在精確範圍內使用不就精確了。但,是這樣嗎?
#include "stdio.h"
int main(void){
  float a = 0.3;
  printf("%f",a*3000000000000000);//你以為輸出的是900000000000000嗎?
}
--------------------------------結果---------------------------------
900000062111744.000000
  沒錯,就是這樣細微的差別,經過大量計算或是大數計算後,會產生不一樣的結果,這對於一個需要精確數字的專案來說是很傷的。

速度問題

  由於十進位小數轉二進位小數,必須不斷的計算直到做到逼近值,要知道這種計算是相當困難的,雖說現今大多cpu有為浮點數做專門的運算,但實際上還是比整數運算慢了些。
#include "stdio.h"
#include "sys/time.h"
int main(void){
  struct timeval begin, end;
  gettimeofday(&begin, 0);
  float a = 0.3;
  for(int i =0;i<100000000;i++){
    a++;
    a++;
    a--;
    a--;
  }
  gettimeofday(&end, 0);
  long seconds = end.tv_sec - begin.tv_sec;
  long microseconds = end.tv_usec - begin.tv_usec;
  double elapsed = seconds + microseconds*1e-6;
  printf("Time measured: %.3f seconds.\n", elapsed);
  return 0;
}
--------------------------------結果---------------------------------
Time measured: 1.139 seconds.
-------------------------------分隔線--------------------------------
#include "stdio.h"
#include "sys/time.h"
int main(void){
  struct timeval begin, end;
  gettimeofday(&begin, 0);
  int a = 3;
  for(int i =0;i<100000000;i++){
    a++;
    a++;
    a--;
    a--;
  }
  gettimeofday(&end, 0);
  long seconds = end.tv_sec - begin.tv_sec;
  long microseconds = end.tv_usec - begin.tv_usec;
  double elapsed = seconds + microseconds*1e-6;
  printf("Time measured: %.3f seconds.\n", elapsed);
  return 0;
}
--------------------------------結果---------------------------------
Time measured: 0.730 seconds.
(這邊採用CR Ferreira的計算時間方式)
  上方整數與浮點數的運算中,我們可以看出整數運算還是比浮點數快了些。

結論

  雖說浮點數有以上缺點,但只要排除這些問題,使用上還是可以的。假設今天你的專案不需要精確的數字,或是在精確位數內運算的,都還是可以使用浮點數。至於速度問題,雖然整數運算以及浮點數運算本身就是兩種不同的東西,但倘若兩種運算都可以達到目的的情況下,還是建議使用整數運算的好。
為什麼會看到廣告
avatar-img
12會員
18內容數
這裡是來自 高科大 資管系二年級的學生,希望能在學習的過程中,也分享這些知識給大家。
留言0
查看全部
avatar-img
發表第一個留言支持創作者!
咖啡因學習教室 的其他內容
說明 重點 △定義變數 △文字的定義 △文字與數字的差別 △整數與浮點數 △signed(有號)與unsigned(無號)的區別 △e是什麼符號? 分類 △字元 △字串 △短整數 △整數 △長整數 △超長整數 △單精度浮點數 △雙精度浮點數 △長雙精度浮點數 應用 宣告與輸出 運算符 結論
前言 輸出 printf 格式控制字元、格式控制符(format char) 前言 輸出控制字元、輸出控制符 轉義字元、轉義符 格式控制字元、格式控制符 輸入 scanf gets gets與scanf差異
auto(自動)、register(暫存器)、static(靜態)、extern(外部),以作用範圍(scope)、存儲時期(life time)、連結(linkage)的不同作為區別。
說明 重點 △定義變數 △文字的定義 △文字與數字的差別 △整數與浮點數 △signed(有號)與unsigned(無號)的區別 △e是什麼符號? 分類 △字元 △字串 △短整數 △整數 △長整數 △超長整數 △單精度浮點數 △雙精度浮點數 △長雙精度浮點數 應用 宣告與輸出 運算符 結論
前言 輸出 printf 格式控制字元、格式控制符(format char) 前言 輸出控制字元、輸出控制符 轉義字元、轉義符 格式控制字元、格式控制符 輸入 scanf gets gets與scanf差異
auto(自動)、register(暫存器)、static(靜態)、extern(外部),以作用範圍(scope)、存儲時期(life time)、連結(linkage)的不同作為區別。
你可能也想看
Google News 追蹤
Thumbnail
隨著理財資訊的普及,越來越多台灣人不再將資產侷限於台股,而是將視野拓展到國際市場。特別是美國市場,其豐富的理財選擇,讓不少人開始思考將資金配置於海外市場的可能性。 然而,要參與美國市場並不只是盲目跟隨標的這麼簡單,而是需要策略和方式,尤其對新手而言,除了選股以外還會遇到語言、開戶流程、Ap
Thumbnail
嘿,大家新年快樂~ 新年大家都在做什麼呢? 跨年夜的我趕工製作某個外包設計案,在工作告一段落時趕上倒數。 然後和兩個小孩過了一個忙亂的元旦。在深夜時刻,看到朋友傳來的解籤網站,興致勃勃熬夜體驗了一下,覺得非常好玩,或許有人玩過了,但還是想寫上來分享紀錄一下~
1. 什麼是浮點數? 浮點數是一種用來表示小數或非常大的數字的方法。 它的作用是讓電腦能夠處理像 3.14159(圓周率)或 1234567890(很大的數字)這樣的數字。 為什麼要有浮點數? 👉 因為用電腦表示這些數字的時候,記憶體有限,直接儲存會很浪費空間,效率也低。 2.
**浮點數(Floating Point, FP)**的概念最早可以追溯到20世紀初,但它在現代計算中的應用則是在電腦科學發展的中期開始逐漸普及。 1. 浮點數的起源 早期數值表示: 在 20 世紀初,數值運算主要依賴定點數(Fixed Point)表示法,這種方式限制了數值的範圍和精度,尤
Thumbnail
我們在上一篇簡單介紹了 int(整數)是做什麼用的,接下來要介紹常和他一起出現的好朋友 float 浮點數 跟 str 字串。 float 浮點數: 函數的式子寫做 float( ) ,浮點數就是帶有小數點的資料型別,他可以將字串或是數字轉換為有小數點的狀態。前提是字串內的字符必須是數字的格
Thumbnail
數位IC裡我們關注的都是0或1, 大家都知道電腦是0101在做二進位的運算, 在晶片裡又是怎麼做到的? 實際上我們在設計晶片時,會給他一個VDD跟GND, VDD-GND給的是預期的Driving volatge, 像是5V或9V 以5V為例 0或1物理上就是目前的電壓靠近0V或5
Thumbnail
本文詳細介紹了Python中的各種資料型別,包括整數、字串、清單、元組、集合和字典,並提供了相關的操作範例。此外,還解釋了如何在Python中定義和操作變數,包括如何同時對多個變數進行賦值。
Thumbnail
題目敘述 輸入給定一個鏈結串列,整體看代表一個十進位的數字,各別看每個節點代表每個digit,分別從最高位~最低位個位數。 要求我們把原本的數字乘以二,並且以鏈結串列的形式返回答案。 原本的英文題目敘述
Thumbnail
這篇文章,會帶著大家複習以前學過的二進位DP框架, 並且以0~N的整數有幾個bit1,有幾個bit0的概念為核心, 貫穿一些相關聯的題目,透過框架複現來幫助讀者理解這個演算法框架。 常見的考法 請問整數k有幾個bit1? 有幾個bit0? 請問整數0到整數N分別各有幾個bit1? 有幾個
Thumbnail
該文章介紹了浮點數精度的概念,包括雙精度、單精度、半精度、8位精度、4位精度、量化精度、多精度和混合精度。同時還介紹了nVidia A100開始的TF32精度和BF16格式,並提供了相關的數據對比。文章強調了TF32和BF16的潛在應用價值及特點。
Thumbnail
在Python中,數值運算非常直觀,你可以使用標準的數學運算符號進行基本的數值運算。以下是一些基本的數值運算: 進行計算時,按照「先乘除後加減」的規則,並優先計算小括號刮起來的運算式。 print('答案:' ,(1+1)*2) #​答案: 4 復合型態的運算子 指定運算子 = 若是結合算術
Thumbnail
隨著理財資訊的普及,越來越多台灣人不再將資產侷限於台股,而是將視野拓展到國際市場。特別是美國市場,其豐富的理財選擇,讓不少人開始思考將資金配置於海外市場的可能性。 然而,要參與美國市場並不只是盲目跟隨標的這麼簡單,而是需要策略和方式,尤其對新手而言,除了選股以外還會遇到語言、開戶流程、Ap
Thumbnail
嘿,大家新年快樂~ 新年大家都在做什麼呢? 跨年夜的我趕工製作某個外包設計案,在工作告一段落時趕上倒數。 然後和兩個小孩過了一個忙亂的元旦。在深夜時刻,看到朋友傳來的解籤網站,興致勃勃熬夜體驗了一下,覺得非常好玩,或許有人玩過了,但還是想寫上來分享紀錄一下~
1. 什麼是浮點數? 浮點數是一種用來表示小數或非常大的數字的方法。 它的作用是讓電腦能夠處理像 3.14159(圓周率)或 1234567890(很大的數字)這樣的數字。 為什麼要有浮點數? 👉 因為用電腦表示這些數字的時候,記憶體有限,直接儲存會很浪費空間,效率也低。 2.
**浮點數(Floating Point, FP)**的概念最早可以追溯到20世紀初,但它在現代計算中的應用則是在電腦科學發展的中期開始逐漸普及。 1. 浮點數的起源 早期數值表示: 在 20 世紀初,數值運算主要依賴定點數(Fixed Point)表示法,這種方式限制了數值的範圍和精度,尤
Thumbnail
我們在上一篇簡單介紹了 int(整數)是做什麼用的,接下來要介紹常和他一起出現的好朋友 float 浮點數 跟 str 字串。 float 浮點數: 函數的式子寫做 float( ) ,浮點數就是帶有小數點的資料型別,他可以將字串或是數字轉換為有小數點的狀態。前提是字串內的字符必須是數字的格
Thumbnail
數位IC裡我們關注的都是0或1, 大家都知道電腦是0101在做二進位的運算, 在晶片裡又是怎麼做到的? 實際上我們在設計晶片時,會給他一個VDD跟GND, VDD-GND給的是預期的Driving volatge, 像是5V或9V 以5V為例 0或1物理上就是目前的電壓靠近0V或5
Thumbnail
本文詳細介紹了Python中的各種資料型別,包括整數、字串、清單、元組、集合和字典,並提供了相關的操作範例。此外,還解釋了如何在Python中定義和操作變數,包括如何同時對多個變數進行賦值。
Thumbnail
題目敘述 輸入給定一個鏈結串列,整體看代表一個十進位的數字,各別看每個節點代表每個digit,分別從最高位~最低位個位數。 要求我們把原本的數字乘以二,並且以鏈結串列的形式返回答案。 原本的英文題目敘述
Thumbnail
這篇文章,會帶著大家複習以前學過的二進位DP框架, 並且以0~N的整數有幾個bit1,有幾個bit0的概念為核心, 貫穿一些相關聯的題目,透過框架複現來幫助讀者理解這個演算法框架。 常見的考法 請問整數k有幾個bit1? 有幾個bit0? 請問整數0到整數N分別各有幾個bit1? 有幾個
Thumbnail
該文章介紹了浮點數精度的概念,包括雙精度、單精度、半精度、8位精度、4位精度、量化精度、多精度和混合精度。同時還介紹了nVidia A100開始的TF32精度和BF16格式,並提供了相關的數據對比。文章強調了TF32和BF16的潛在應用價值及特點。
Thumbnail
在Python中,數值運算非常直觀,你可以使用標準的數學運算符號進行基本的數值運算。以下是一些基本的數值運算: 進行計算時,按照「先乘除後加減」的規則,並優先計算小括號刮起來的運算式。 print('答案:' ,(1+1)*2) #​答案: 4 復合型態的運算子 指定運算子 = 若是結合算術