.丟棄小數部分,保留整數部分
parseInt(5/2)
2.向上取整,有小數就整數部分加1
Math.ceil(5/2)
3,四舍五入.
Math.round(5/2)
4,向下取整
Math.floor(5/2)
責聲明:
我已經盡量簡化了,由于觀看本節內容導致的頭暈、脫發、惡心、嘔吐等生理癥狀,本人概不負責
在現實世界中,小數的書寫方式非常自然,只需要使用.即可代表之后的數字全是小數,例如3.1415926
但是計算機存儲小數的時候,麻煩就來了。
比如3.14,整數部分的二進制是11,小數部分的二進制是1011,合在一起就是111011,你能說這個數是3.14嗎?
問題的根源就在它難以準確的表述小數點的位置。
因此,必須另尋他法。
浮點數基本概念
聰明的人想出了一個巧妙的辦法
在現實世界中,任何數字都可以表示為a.xxxx * 10^na.xxxx?10n,其中,a的取值范圍是1~9
這叫做科學計數法
比如:
1024.5678=1.0245678 * 10^31024.5678=1.0245678?103,它表示,1.0245678的小數點向右移動3位,即最終的十進制小數
952.7=9.527 * 10^2952.7=9.527?102,它表示,9.527的小數點向右移動2位,即最終的十進制小數
那二進制是否也可以這樣表示呢?
當然可以,在二進制的世界中,任何數字(包括整數)都可以表示為a.xxxx * 2^na.xxxx?2n,a只能取1
比如:
110.101=1.10101 * 2^2110.101=1.10101?22,它表示,1.10101的小數點向右移動2位,即最終的二進制小數
0010.00011=1.000011 * 2^10010.00011=1.000011?21,它表示,1.000011的小數點向右移動1位,即最終
的二進制小數
可以看出,二進制如果也使用科學計數法,以下東西都是固定的:
底數2
整數部分1
而不固定的部分是:
指數部分
尾數部分(小數點后面的部分)
因此,我們可以使用下面的方式來表示一個數字
第一部分第二部分第三部分
符號 階碼 尾數
0為正,1為負 這部分表示指數部分 這部分表示小數點后面的部分
這種表示數字的方法,叫做浮點數表示法
比如,110.101=1.10101 * 2^2110.101=1.10101?22,改數字的符號是0,階碼是2,階碼的二進制格式是10,尾數是10101,因此,在計算機中可以用浮點數表示為:
符號階碼尾數
0 10 10101
是不是很簡單。
但這樣一來,容易導致CPU搞不清楚階碼和尾數是在哪里分割的,我們可以輕松的從表格中看出,但計算機哪有什么表格,它是存在一起的:01010101
為了解決這個問題,階碼和尾數的長度就必須固定
比如,階碼的長度規定為3,尾數的長度規定為4,加上一個符號位,剛好是8位,一個字節
如果按照這種約定,計算機就可以輕松的取出第一個符號位,然后輕松的取出后三位階碼,繼續取出后四位的尾數
符號(1)階碼(3)尾數(4)
0 010 1010
可以看到,這種情況下,尾數的最后一位被丟棄了,從10101變成了1010,因為它只能存儲4位。
所以,使用浮點數存儲數字時,可能導致存儲的數字不精確
以上,就是浮點數存儲數字的方式。
數字到浮點數的轉換
我們知道,二進制科學計數法是浮點數的基石,只要有了二進制的科學計數法,就可以變成浮點數的存儲了。
然而,我們平時接觸更多的是十進制的小數
現在的問題是:如何把十進制的小數轉換為浮點數的科學計數法?
下面將一步一步進行分析
二進制小數到十進制小數
要理解十進制小數是如何轉換成二進制小數的,就必須要先理解相反的情況:二進制小數是如何轉換成十進制小數的。
我們知道,任何一個十進制的小數(包括整數)都可以書寫為下面的格式:
21.25=2 * 10^1 + 1 * 10^0 + 2 * 10^{-1} + 2 * 10^{-2}21.25=2?101+1?100+2?10?1+2?10?2
二進制的小數也可以用同樣的規則,只不過把底數10換成底數2
下面的示例就是把一個二進制小數11.01轉換成了十進制小數3.25:
11.01_2=1 * 2^1 + 1 * 2^0 + 0 * 2^{-1} + 1 * 2^{-2}=3.25_{10}11.012=1?21+1?20+0?2?1+1?2?2=3.2510
十進制小數到二進制小數
知道了二進制小數轉十進制,反過來也是一樣的
省略了具體的數學推導(數學好的朋友自行完成),我們按照下面的方式來轉換
比如十進制數3.25
首先轉換整數部分:
3_{10}=11310=11
整數部分的轉換在之前的章節已經說的很詳細了,不再重復
然后轉換小數部分
現有小數乘以2取整數部分
0.25 0.5 0
0.5 1 1
0 不再處理 不再處理
最終得到的二進制小數部分是01,即把每次取整部分從上到下依次羅列即可
0.25_{10}=0.01_20.2510=0.012
把最終的整數部分加入進去,就形成了
3.25_{10}=11.01_{2}3.2510=11.012
無法精確轉換
有的時候,這種轉換是無法做到精確的
比如0.3這個十進制數,轉換成二進制小數按照下面的過程進行
現有小數乘以2取整數部分
0.3 0.6 0
0.6 1.2 1
0.2 0.4 0
0.4 0.8 0
0.8 1.6 1
0.6 1.2 1
0.2 0.4 0
0.4 0.8 0
0.8 1.6 1
0.6 1.2 1
... ... ...
0.3_{10}=0.0 1001 1001 1001 1001 ...=0.0\overline{1001}0.310=0.01001100110011001...=0.01
在轉換的過程中,可能導致十進制的現有小數永遠無法歸零,于是轉換成了一個無限的二進制小數。
同時,計算機無法存儲一個無限的數據,因此,總有一些數據會被丟棄,這就造成了計算機存儲的小數部分可能是不精確的
進一步,如果一個小數無法精確的存儲,那么他們之間的運算結果也是不精確的
這就是計算機對小數的運算不精確的原因
// js語言中運行5.3 - 5.2 // 得到0.09999999999999964
轉換成二進制的科學計數
現在,按照以上所述的規則,我們已經可以輕松的把一個十進制的數字轉換成二進制格式了
然后,我們再在它的基礎上,把它變化為二進制的科學計數格式
3.25_{10}=11.01_2=1.101 * 2^13.2510=11.012=1.101?21
注意,1.101 * 2^11.101?21是二進制的科學計數表示,你并不能把它當成十進制的方式運算,如果你要將其轉換成十進制,應該:
將1.101的小數點向右移動1位,得到11.01
.01=1
2^1 + 1
2^0 + 0
2^{-1} + 1
2^{-2}=3.25$
當我們拿到這個數的二進制科學計數后,就可以輕松的將其存儲下來了
3.25=11.01=1.101 * 2^1=1.1010 * 2^13.25=11.01=1.101?21=1.1010?21的存儲
因為尾數是4位,所以不足在后面補0
符號(1)階碼(3)尾數(4)
0 001 1010
然而
請允許我做一個悲傷的表情
還有一種情況沒有考慮到...
指數偏移量
建議先讀完本節內容,然后再反復推理和思考
我們來聊一聊還有什么情況沒有考慮到
現在,我們有一個十進制的數字0.25,它轉換成二進制的格式應該是0.01,科學計數法表示的結果是1*2^{-2}1?2?2,即小數點應該向左移動2位
現在的問題是,指數部分出現了負數!
注意,不是數字是負數,是指數是負數
問題在于,我難道對指數也要使用一個符號位來處理負數的情況嗎?
實際上沒有必要,在計算機運算浮點數時,對于指數部分,更多的操作是比較,即比較兩個指數哪個大
如果使用符號位的話,在比較時就必須考慮符號的問題,這樣會給比較帶來很多麻煩
因此,IEEE 754規定,使用指數偏移量來處理這個問題
IEEE 754是對浮點數存儲、運算的國際標準,絕大部分計算機語言的浮點數都遵循該標準
它規定,如果一個浮點數的指數位數為ee,則它的指數偏移量為2^{e - 1} - 12e?1?1,不管存儲什么指數值,都需要加上這個偏移量后再進行存儲。
比如,指數的位數是3,則指數的偏移量為2^{3-1} - 1=323?1?1=3,當存儲指數-2時,需要加上偏移量3再進行存儲,因此,指數-2實際上存儲的是1,即001
再比如,當存儲指數2時,需要加上偏移量3再進行存儲,因此,指數2實際上存儲的是5,即101
如果比較-2和2哪個大,就直接比較兩個二進制即可,001顯然比101要小,指數部分完全沒有符號位,這樣比較起來就輕松多了。
當然,當需要還原它的真實指數時,只需要減去偏移量即可
于是,有了這樣的規則后:
0.25_{10}=0.01_2=1.0000 * 2^{-2}0.2510=0.012=1.0000?2?2
符號(1)階碼(3)尾數(4)
0 001 0000
3.25_{10}=11.01_2=1.1010 * 2^13.2510=11.012=1.1010?21
符號(1)階碼(3)尾數(4)
0 100 1010
由于有了偏移量的存在,浮點數的指數范圍就可以很輕松的算出來了
最小能存儲的指數是000,減去偏移量后真實的指數是-3
最大能存儲的指數是111,減去偏移量后真實的指數是4
稍微的總結一下,就是:
階碼為n位的浮點數,指數的真實范圍是-2^{n-1}+1?2n?1+1 到 2^{n-1}2n?1
特殊值
在浮點數的標準中,有下面兩個特殊值:
NaN:Not a Number,表示不是一個數字,它通常來自一些錯誤的運算,比如
3.14 * "你好"
Infinity:正向的無窮大,相當于數學中的
\infty
∞
-Infinity:負向的無窮大,相當于數學中的
-\infty
?
∞
為了表示這三個值,IEEE 754標準規定,當使用一種特殊的數字存儲來表示:
NaN
符號(1)階碼(3)尾數(4)
無所謂
比如:
符號(1)階碼(3)尾數(4)
0 111 1010
上面這個數字可不是1.1010*2^{4}1.1010?24,它是一個NaN
無窮
符號(1)階碼(3)尾數(4)
0:正無窮,1:負無窮 111
比如:
符號(1)階碼(3)尾數(4)
0 111 0000
上面這個數字可不是1.0000*2^{4}1.0000?24,它是一個Infinity
由于特殊值的存在,讓階碼的最大值用于表示特殊值,因此,正常的數字階碼是不能取到最大值的
因此,正常數字的階碼取值范圍少了一個:-2^{n-1}+1?2n?1+1 到 2^{n-1} - 12n?1?1
比如,3位的階碼,它能表示的正常指數范圍是-3到3
單精度和雙精度
很多計算機語言中都有單精度和雙精度的概念,它們的區別在于階碼和尾數的位數是不一樣的
Java的float是單精度浮點數,double是雙精度浮點數
JS的所有數字均為雙精度浮點數
類型符號階碼尾數共計
單精度 1位 8位 23位 32bit,4byte
雙精度 1位 11位 52位 64bit,8byte
總結
由于浮點數這種特別的存儲方式,因此,不同的階碼和尾數的位數,決定了:
階碼位數越多,可以取到的指數越大,因此可以表示的數字越大
尾數位數越多,可以表示的數字位數越多,因此可以表示的更加精確
本次學習目標
在1995年時,由Netscape公司的Brendan Eich,在網景導航者瀏覽器上首次設計實現而成。Netscape在最初將其腳本語言命名為LiveScript,因為Netscape與Sun合作,網景公司管理層希望蹭Java的熱度,因此取名為JavaScript。
JavaScript總共分成三部分: ECMAScript(基本語法)、BOM(瀏覽器對象模型)、DOM(文檔對象模型)
JavaScript是一種解釋型的腳本語言。不同于C、C++、Java等語言先編譯后執行, JavaScript不會產生編譯出來的字節碼文件,而是在程序的運行過程中對源文件逐行進行解釋。
JavaScript是一種基于對象的腳本語言,它不僅可以創建對象,也能使用現有的對象。但是面向對象的三大特性:『封裝』、『繼承』、『多態』中,JavaScript能夠實現封裝,可以模擬繼承,不支持多態,所以它不是一門面向對象的編程語言。
JavaScript中也有明確的數據類型,但是聲明一個變量后它可以接收任何類型的數據,并且會在程序執行過程中根據上下文自動轉換類型。
JavaScript是一種采用事件驅動的腳本語言,它不需要經過Web服務器就可以對用戶的輸入做出響應。
JavaScript腳本語言不依賴于操作系統,僅需要瀏覽器的支持。因此一個JavaScript腳本在編寫后可以帶到任意機器上使用,前提是機器上的瀏覽器支持JavaScript腳本語言。目前JavaScript已被大多數的瀏覽器所支持。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>JS的入門程序</title>
</head>
<body>
<!-- 在HTML代碼中定義一個按鈕 -->
<button type="button" id="helloBtn">SayHello</button>
<!--
目標: 點擊按鈕的時候彈出一個警告框
-->
<script type="text/javascript">
//1. 通過js代碼獲取到按鈕對象
//document代表當前HTML文檔
var btn=document.getElementById("helloBtn");
//2. 給獲取到的btn對象綁定點擊事件
btn.onclick=function () {
//彈出警告框
alert("hello world");
}
*請認真填寫需求信息,我們會在24小時內與您取得聯系。