0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
电子发烧友
开通电子发烧友VIP会员 尊享10大特权
海量资料免费下载
精品直播免费看
优质内容免费畅学
课程9折专享价
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

計(jì)算機(jī)系統(tǒng)對(duì)數(shù)值類型的編碼、運(yùn)算、轉(zhuǎn)換原理介紹4

jf_78858299 ? 來源:元閏子的邀請(qǐng) ? 作者:元閏子 ? 2023-05-09 16:31 ? 次閱讀

數(shù)值類型轉(zhuǎn)換

數(shù)值類型間的轉(zhuǎn)換,可以分成 2 類: 寬轉(zhuǎn)換 (Widening Conversion)和 窄轉(zhuǎn)換 (Narrowing Conversion)。

寬轉(zhuǎn)換指往表示范圍更廣的類型轉(zhuǎn)換,比如從 int 到 long、從 long 到 float;窄轉(zhuǎn)換則相反。

整型間轉(zhuǎn)換

(1)寬轉(zhuǎn)換

整型間的寬轉(zhuǎn)換不會(huì)產(chǎn)生溢出,無(wú)符號(hào)整數(shù)場(chǎng)景,高位補(bǔ)零;有符號(hào)整數(shù)場(chǎng)景,高位補(bǔ)符號(hào)位。

// C++
int main() {
    int8_t i1 = 100;
    cout << "int8_t  i1: " << bitset<8>(i1) << endl;
    cout << "int16_t i1: " << bitset<16>((int16_t) i1) << endl;

    int8_t i2 = -100;
    cout << "int8_t  i2: " << bitset<8>(i2) << endl;
    cout << "int16_t i2: " << bitset<16>((int16_t) i2) << endl;

    uint8_t i3 = 200;
    cout << "uint8_t  i3: " << bitset<8>(i3) << endl;
    cout << "uint16_t i3: " << bitset<16>((uint16_t) i3) << endl;
    return 0;
}
// 輸出結(jié)果
int8_t  i1: 01100100
int16_t i1: 0000000001100100
int8_t  i2: 10011100
int16_t i2: 1111111110011100
uint8_t  i3: 11001000
uint16_t i3: 0000000011001000

(2)窄轉(zhuǎn)換

整型間的窄轉(zhuǎn)換直接進(jìn)行高位截?cái)?,只保留?n 位。比如 16 位的 int16 轉(zhuǎn)換為 8 位的 int8,直接保留 int16 類型值的低 8 位作為轉(zhuǎn)換結(jié)果。

// C++
int main() {
    int16_t i1 = 200;
    cout << "int16_t i1: " << bitset<16>(i1) << endl;
    cout << "int8_t  i1: " << bitset<8>((int8_t) i1) << endl;

    int16_t i2 = -200;
    cout << "int16_t i2: " << bitset<16>(i2) << endl;
    cout << "int8_t  i2: " << bitset<8>((int8_t) i2) << endl;

    uint16_t i3 = 300;
    cout << "uint16_t i3: " << bitset<16>(i3) << endl;
    cout << "uint8_t  i3: " << bitset<8>((uint8_t) i3) << endl;
    return 0;
}
// 輸出結(jié)果
int16_t i1: 0000000011001000
int8_t  i1: 11001000
int16_t i2: 1111111100111000
int8_t  i2: 00111000
uint16_t i3: 0000000100101100
uint8_t  i3: 00101100

(3)無(wú)符號(hào)整數(shù)與有符號(hào)整數(shù)間的轉(zhuǎn)換

無(wú)符號(hào)整數(shù)與有符號(hào)整數(shù)間的轉(zhuǎn)換規(guī)則是:

  • 如果兩者二進(jìn)制位數(shù)一致,比如 int8uint8 的轉(zhuǎn)換,則二進(jìn)制數(shù)值不變,只是改變編碼方式;
  • 如果位數(shù)不一致,比如 int16uint8 的轉(zhuǎn)換,則二進(jìn)制數(shù)值,先按照寬轉(zhuǎn)換或窄轉(zhuǎn)換規(guī)則轉(zhuǎn)換,再改變編碼方式。
// C++
int main() {
    uint8_t i1 = 200;
    cout << "uint8_t i1, decimal: " << +i1 << ", binary: " << bitset<8>(i1) << endl;
    cout << "int8_t  i1, decimal: " << +(int8_t) i1 << ", binary: " << bitset<8>((int8_t) i1) << endl;

    int16_t i2 = -300;
    cout << "int16_t i2, decimal: " << +i2 << ", binary: " << bitset<16>(i2) << endl;
    cout << "uint8_t i2, decimal: " << +(uint8_t) i2 << ",  binary: " << bitset<8>((uint8_t) i2) << endl;
    return 0;
}
// 輸出結(jié)果
uint8_t i1, decimal: 200, binary: 11001000
int8_t  i1, decimal: -56, binary: 11001000
int16_t i2, decimal: -300, binary: 1111111011010100
uint8_t i2, decimal: 212,  binary: 11010100

整數(shù)與浮點(diǎn)數(shù)間轉(zhuǎn)型

(1)寬轉(zhuǎn)換

整型到浮點(diǎn)數(shù)類型的轉(zhuǎn)換這一方向,為寬轉(zhuǎn)換:

  • 如果浮點(diǎn)數(shù)的精度,能夠表示整數(shù),則正常轉(zhuǎn)換。
  • 如果浮點(diǎn)數(shù)精度,無(wú)法表示整數(shù),則需要近似,會(huì)導(dǎo)致精度丟失。
// Java
public static void main(String[] args) {
    int i1 = 1234567;
    System.out.printf("int i1: %d, float i1: ", i1);
    System.out.println((float) i1);

    int i2 = 123456789;
    System.out.printf("int i2: %d, float i2: ", i2);
    System.out.println((float) i2);
}
// 輸出結(jié)果
int i1: 1234567, float i1: 1234567.0
int i2: 123456789, float i2: 1.23456792E8

上述例子中,i2=123456789 超過 float 類型能夠表示的精度,所以為近似后的結(jié)果 1.23456792E8

那么,為什么 123456789 會(huì)近似為 1.23456792E8?

要解釋該問題,首先要把它們轉(zhuǎn)換成二進(jìn)制表示:

public static void main(String[] args) {
    ...
    System.out.println("int i2:   " + int2BinaryStr(i2));
    System.out.println("float i2: " + float2BinaryStr((float) i2));
}
// 輸出結(jié)果
int i2:   00000111010110111100110100010101
float i2: 01001100111010110111100110100011

接下來,我們根據(jù) IEEE 浮點(diǎn)數(shù)的編碼規(guī)則,嘗試將 int i2 轉(zhuǎn)換成 float i2

  1. int i2 的二進(jìn)制 ,可以寫成 ,對(duì)應(yīng)到 的形式,可以確認(rèn) s = 0,E = 26,M = 1.11010110111100110100010101。
  2. float 類型中 k = 8,有,,得出 e = 153,按 k 位無(wú)符號(hào)編碼表示為 。
  3. 同理,由 ,但由于 float 類型的 n = 23,而 m 一共有 26 位,因此需要按照 round-to-even 規(guī)則,對(duì) 0.11010110111100110100010101進(jìn)行近似,保留 23 位小數(shù),得到 0.11010110111100110100011,所以 m 為
  4. 最后,將 s、e、m 按照 float 單精度的編碼格式組合起來,就是 ,轉(zhuǎn)換成十進(jìn)制,就是 1.23456792E8

(2)窄轉(zhuǎn)換

浮點(diǎn)數(shù)類型到整型的轉(zhuǎn)換這一方向,為窄轉(zhuǎn)換:

  • 如果浮點(diǎn)數(shù)的整數(shù)部分,能夠用整型表示,則直接舍去小數(shù),保留整數(shù)部分。
  • 如果超出了整型范圍,則結(jié)果為該整型的最大/最小值。
// Java
public static void main(String[] args) {
    float f1 = 12345.123F;
    System.out.print("float f1: ");
    System.out.print(f1);
    System.out.printf(",  int f1: %d\\n", (int) f1);

    float f2 = 1.2345E20F;
    System.out.print("float f2: ");
    System.out.print(f2);
    System.out.printf(",  int f2: %d\\n", (int) f2);

    float f3 = -1.2345E20F;
    System.out.print("float f3: ");
    System.out.print(f3);
    System.out.printf(", int f3: %d\\n", (int) f3);
 }
// 輸出結(jié)果
float f1: 12345.123,  int f1: 12345
float f2: 1.2345E20,  int f2: 2147483647
float f3: -1.2345E20, int f3: -2147483648

浮點(diǎn)數(shù)間轉(zhuǎn)型

(1)寬轉(zhuǎn)換

單精度 float 到 雙精度 double 為寬轉(zhuǎn)換,不會(huì)出現(xiàn)精度丟失的問題。

對(duì)于 ,規(guī)則如下:

  • s 保持不變。
  • 在 E 保持不變的前提下,因?yàn)?float 的 k = 8,而 double 的 k = 11,所以兩者的 e 會(huì)有所不同。
  • 在 M 保持不變的前提下,float 的 n = 23,而 double 的 n =52,所以 m 需要低位補(bǔ) 52 - 23 = 29 個(gè) 0。
// Java
public static void main(String[] args) {
    float f1 = 1.2345E20F;
    System.out.print("float  f1: ");
    System.out.print(f1);
    System.out.print(", double f1: ");
    System.out.println((double) f1);

    System.out.println("float  f1: " + float2BinaryStr(f1));
    System.out.println("double f1: " + double2BinaryStr((double) f1));
}
// 輸出結(jié)果
float  f1: 1.2345E20, double f1: 1.2344999897320129E20
float  f1: 01100000110101100010011011010000
double f1: 0100010000011010110001001101101000000000000000000000000000000000

圖片

(2)窄轉(zhuǎn)換

doublefloat 為窄轉(zhuǎn)換,會(huì)存在精度丟失問題。

如果 double 值超出了 float 的表示范圍,則轉(zhuǎn)換結(jié)果為 Infinity

// Java
public static void main(String[] args) {
    double d1 = 1E200;
    System.out.print("double d1: ");
    System.out.println(d1);
    System.out.print("float d1: ");
    System.out.println((float) d1);

    double d2 = -1E200;
    System.out.print("double d2: ");
    System.out.println(d2);
    System.out.print("float d2: ");
    System.out.println((float) d2);
 }
// 輸出結(jié)果
double d1: 1.0E200
float d1: Infinity
double d2: -1.0E200
float d2: -Infinity

如果 double 值還在 float 的表示范圍內(nèi),則按照如下轉(zhuǎn)換規(guī)則:

  • s 保持不變。
  • 在 E 保持不變的前提下,因?yàn)?float 的 k = 8,而 double 的 k = 11,所以兩者的 e 會(huì)有所不同。
  • 對(duì)于 M,因?yàn)?float 的 n = 23,而 double 的 n = 52,所以轉(zhuǎn)換到 float 之后,需要進(jìn)行截?cái)?,只保留?23 位。
// Java
public static void main(String[] args) {
    double d1 = 3.267393471324506;
    System.out.print("double d1: ");
    System.out.println(d1);
    System.out.print("float  d1: ");
    System.out.println((float) d1);
    System.out.println("double d1: " + double2BinaryStr(d1));
    System.out.println("float  d1: " + float2BinaryStr((float) d1));
}
// 輸出結(jié)果
double d1: 3.267393471324506
float  d1: 3.2673936
double d1: 0100000000001010001000111001111100110000001101000000010101110110
float  d1: 01000000010100010001110011111010

圖片

最后

本文花了很長(zhǎng)的篇幅,深入介紹了計(jì)算機(jī)系統(tǒng)對(duì)數(shù)值類型的編碼、運(yùn)算、轉(zhuǎn)換的底層原理。

數(shù)值類型間的轉(zhuǎn)換是最容易出現(xiàn)隱藏 bug 的地方 ,特別是無(wú)符號(hào)整數(shù)與有符號(hào)整數(shù)之間的轉(zhuǎn)換。所以,很多現(xiàn)代的編程語(yǔ)言,如 Java、Go 等都不再支持無(wú)符號(hào)整數(shù),根除了該隱患。

另外,浮點(diǎn)數(shù)的編碼方式,注定它只能精確表示一小部分的數(shù)值范圍,大部分都是近似,所以才有了不能用等號(hào)來比較兩個(gè)浮點(diǎn)數(shù)的說法。

數(shù)值類型雖然很基礎(chǔ),但使用時(shí)一定要多加小心。希望本文能夠加深你對(duì)數(shù)值類型的理解,讓你寫出更健壯的程序。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 二進(jìn)制
    +關(guān)注

    關(guān)注

    2

    文章

    801

    瀏覽量

    41790
  • 計(jì)算機(jī)
    +關(guān)注

    關(guān)注

    19

    文章

    7559

    瀏覽量

    88821
  • 編程
    +關(guān)注

    關(guān)注

    88

    文章

    3643

    瀏覽量

    94126
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    計(jì)算機(jī)系統(tǒng)結(jié)構(gòu)

    計(jì)算機(jī)系統(tǒng)結(jié)構(gòu)
    發(fā)表于 05-09 19:03

    什么是計(jì)算機(jī)系統(tǒng)、計(jì)算機(jī)硬件和計(jì)算機(jī)軟件?

    第一章 計(jì)算機(jī)系統(tǒng)概論1. 什么是計(jì)算機(jī)系統(tǒng)、計(jì)算機(jī)硬件和計(jì)算機(jī)軟件?硬件和軟件哪個(gè)更重要?解:P3計(jì)算機(jī)系統(tǒng):由
    發(fā)表于 07-22 09:06

    什么是計(jì)算機(jī)系統(tǒng)?硬件和軟件哪個(gè)更重要?

    第一章計(jì)算機(jī)系統(tǒng)概論1 .什么是計(jì)算機(jī)系統(tǒng)、計(jì)算機(jī)硬件和計(jì)算機(jī)軟件?硬件和軟件哪個(gè)更重要?解: P3計(jì)算機(jī)系統(tǒng):由
    發(fā)表于 07-26 07:18

    計(jì)算機(jī)系統(tǒng)中的軟件系統(tǒng)

    專用計(jì)算機(jī)現(xiàn)代計(jì)算機(jī)運(yùn)算速度最高可達(dá)每秒幾萬(wàn)億次幾十億次幾億次幾萬(wàn)次計(jì)算機(jī)輔助制造是計(jì)算機(jī)應(yīng)用領(lǐng)域之一其英文縮寫是所謂的信息是指基本素材非數(shù)值
    發(fā)表于 09-13 07:22

    嵌入式計(jì)算機(jī)系統(tǒng)概述

    硬件子系統(tǒng)和軟件子系統(tǒng)組成的,通過運(yùn)行程序來協(xié)同工作計(jì)算機(jī)硬件:基本的計(jì)算機(jī)硬件系統(tǒng)運(yùn)算器、控
    發(fā)表于 12-22 06:08

    簡(jiǎn)單介紹微型計(jì)算機(jī)的組成

    你了解自己的計(jì)算機(jī)?或者知道單片機(jī)的組成嗎?這一小節(jié)主要簡(jiǎn)單介紹微型計(jì)算機(jī)的組成,以及微型計(jì)算機(jī)系統(tǒng)經(jīng)常用到的概念,包括組成、工作過程、工作原理、數(shù)
    發(fā)表于 01-10 07:11

    計(jì)算機(jī)系統(tǒng)概論

    1.1 計(jì)算機(jī)系統(tǒng)簡(jiǎn)介1.2 計(jì)算機(jī)的基本組成1.3 計(jì)算機(jī)硬件的主要技術(shù)指標(biāo)1.4 本書結(jié)構(gòu)
    發(fā)表于 04-11 09:31 ?0次下載

    微型計(jì)算機(jī)系統(tǒng)

             微型計(jì)算機(jī)系統(tǒng)與傳統(tǒng)的計(jì)算機(jī)系統(tǒng)一樣,也是由硬件系統(tǒng)和軟件系統(tǒng)兩大部分組成的。2.1
    發(fā)表于 03-03 08:31 ?0次下載

    什么是計(jì)算機(jī)系統(tǒng)的容錯(cuò)性

    什么是計(jì)算機(jī)系統(tǒng)的容錯(cuò)性             所謂容錯(cuò)是指在故障存在的情況下計(jì)算機(jī)系統(tǒng)不失效,仍然能夠正常工作的特性
    發(fā)表于 01-08 13:49 ?1643次閱讀

    深入理解計(jì)算機(jī)系統(tǒng)數(shù)值類型

    計(jì)算機(jī)系統(tǒng)中,整數(shù)可以分成 無(wú)符號(hào)(unsigned)整數(shù) 和 有符號(hào)(signed)整數(shù) 兩大類,這之下,按照類型表示的 bit 位大小,又可細(xì)分成 8 位的 char/byte/int8
    的頭像 發(fā)表于 08-19 15:17 ?1270次閱讀

    計(jì)算機(jī)系統(tǒng)對(duì)數(shù)值類型編碼、運(yùn)算、轉(zhuǎn)換原理介紹1

    。正因太熟悉,我們往往不會(huì)深究它們的底層原理。因?yàn)槠綍r(shí)的工作中,知道個(gè)大概,也夠用了。 但,在某些業(yè)務(wù)場(chǎng)景下,比如金融業(yè)務(wù),數(shù)值運(yùn)算不準(zhǔn)確會(huì)帶來災(zāi)難性的后果。這時(shí),你就必須清楚數(shù)值類型
    的頭像 發(fā)表于 05-09 16:30 ?1226次閱讀
    <b class='flag-5'>計(jì)算機(jī)系統(tǒng)</b><b class='flag-5'>對(duì)數(shù)值</b><b class='flag-5'>類型</b>的<b class='flag-5'>編碼</b>、<b class='flag-5'>運(yùn)算</b>、<b class='flag-5'>轉(zhuǎn)換</b>原理<b class='flag-5'>介紹</b>1

    計(jì)算機(jī)系統(tǒng)對(duì)數(shù)值類型編碼、運(yùn)算轉(zhuǎn)換原理介紹2

    。正因太熟悉,我們往往不會(huì)深究它們的底層原理。因?yàn)槠綍r(shí)的工作中,知道個(gè)大概,也夠用了。 但,在某些業(yè)務(wù)場(chǎng)景下,比如金融業(yè)務(wù),數(shù)值運(yùn)算不準(zhǔn)確會(huì)帶來災(zāi)難性的后果。這時(shí),你就必須清楚數(shù)值類型
    的頭像 發(fā)表于 05-09 16:31 ?968次閱讀
    <b class='flag-5'>計(jì)算機(jī)系統(tǒng)</b><b class='flag-5'>對(duì)數(shù)值</b><b class='flag-5'>類型</b>的<b class='flag-5'>編碼</b>、<b class='flag-5'>運(yùn)算</b>、<b class='flag-5'>轉(zhuǎn)換</b>原理<b class='flag-5'>介紹</b>2

    計(jì)算機(jī)系統(tǒng)對(duì)數(shù)值類型編碼、運(yùn)算轉(zhuǎn)換原理介紹3

    。正因太熟悉,我們往往不會(huì)深究它們的底層原理。因?yàn)槠綍r(shí)的工作中,知道個(gè)大概,也夠用了。 但,在某些業(yè)務(wù)場(chǎng)景下,比如金融業(yè)務(wù),數(shù)值運(yùn)算不準(zhǔn)確會(huì)帶來災(zāi)難性的后果。這時(shí),你就必須清楚數(shù)值類型
    的頭像 發(fā)表于 05-09 16:31 ?886次閱讀
    <b class='flag-5'>計(jì)算機(jī)系統(tǒng)</b><b class='flag-5'>對(duì)數(shù)值</b><b class='flag-5'>類型</b>的<b class='flag-5'>編碼</b>、<b class='flag-5'>運(yùn)算</b>、<b class='flag-5'>轉(zhuǎn)換</b>原理<b class='flag-5'>介紹</b>3

    計(jì)算機(jī)系統(tǒng)中的關(guān)鍵組件有哪些

    計(jì)算機(jī)系統(tǒng)中,關(guān)鍵組件的協(xié)同工作構(gòu)成了其強(qiáng)大的數(shù)據(jù)處理和運(yùn)算能力。這些組件不僅決定了計(jì)算機(jī)的性能,還影響著用戶的使用體驗(yàn)。以下是對(duì)計(jì)算機(jī)系統(tǒng)中關(guān)鍵組件的詳細(xì)闡述,包括它們的定義、功能
    的頭像 發(fā)表于 07-15 18:18 ?1839次閱讀

    微處理器如何控制計(jì)算機(jī)系統(tǒng)

    微處理器,作為計(jì)算機(jī)系統(tǒng)的核心部件,承擔(dān)著控制整個(gè)計(jì)算機(jī)系統(tǒng)運(yùn)行的重要任務(wù)。它不僅是計(jì)算機(jī)運(yùn)算中心,還是控制中心,負(fù)責(zé)執(zhí)行程序指令、處理數(shù)據(jù)以及協(xié)調(diào)
    的頭像 發(fā)表于 08-22 14:21 ?632次閱讀

    電子發(fā)燒友

    中國(guó)電子工程師最喜歡的網(wǎng)站

    • 2931785位工程師會(huì)員交流學(xué)習(xí)
    • 獲取您個(gè)性化的科技前沿技術(shù)信息
    • 參加活動(dòng)獲取豐厚的禮品