技术内参 | 数据分析,如何解决精度丢失的问题?
?
?
本文由神策數(shù)據(jù)技術(shù)大咖皮成投稿
談到大數(shù)據(jù)技術(shù),數(shù)據(jù)采集和計算是永遠(yuǎn)繞不開的話題,采集的準(zhǔn)確度、計算的精度都是做數(shù)據(jù)分析的前提條件。
神策數(shù)據(jù)服務(wù)的客戶覆蓋互聯(lián)網(wǎng)各個細(xì)分領(lǐng)域,其中不乏有做目前大火的虛擬貨幣的客戶,比如涉及區(qū)塊鏈和比特幣領(lǐng)域的客戶,從接觸之初,他們對大數(shù)據(jù)工具的要求就極其嚴(yán)苛,當(dāng)然,這與虛擬貨幣自身的特點也分不開。
事實上,每個虛擬貨幣的精確程度小到小數(shù)點后 4 位,大到小數(shù)點后 12 位。客戶在分析用戶每次成交的貨幣量,每日的人均成交貨幣量等指標(biāo),或者在分布分析中查看比持幣的分布情況時,常常是需要精確到小數(shù)點后 8 位甚至更多。
因為虛擬貨幣的單價不同,更高的精確度可以讓客戶更加精準(zhǔn)的細(xì)分出用戶群,進(jìn)而進(jìn)行更深度的分析。高精度確保了分析結(jié)果的準(zhǔn)確性,甚至決定了虛擬貨幣企業(yè)的核心競爭力。
所以,虛擬貨幣企業(yè)對精度的要求極高也不足為奇了。不過,在用 JavaScript 開發(fā)數(shù)據(jù)可視化產(chǎn)品時,會遇到數(shù)值的展現(xiàn)和計算丟失精度的問題,這是很多技術(shù)者想要解決的難題。下面我們從兩方面來為你解決這個問題:
一、為什么會出現(xiàn)精度的丟失?
二、如何解決精度丟失問題?
下面我們先介紹下計算精度的背景:
1. 二進(jìn)制小數(shù)
在十進(jìn)制中,123.45 可以表示為 1 × 102 + 2 × 101 + 3 × 10? + 4 × 10?1 + 5 × 10?2 = 123 ??????,小數(shù)點的位置決定了數(shù)字的權(quán)重,左邊的數(shù)是 10 的正冪,右邊的數(shù)是 10 的負(fù)冪。
類似,二進(jìn)制數(shù) 101.11 也可以表示為 1 × 22 + 0 × 21 + 1 × 2? + 1 × 2?1 + 1 × 2?2 = 4 + 0 + 1 + 1?? + 1?? = 5 3??,小數(shù)點向左移動一位相當(dāng)于這個數(shù)被 2 除,小數(shù)點向右移動一位相當(dāng)于這個數(shù)乘以 2。
在有限的長度下,十進(jìn)制無法準(zhǔn)確表示像 1??、??? 這樣的數(shù),二進(jìn)制也無法準(zhǔn)確表示像 1?? 這樣的數(shù),增加數(shù)字的長度可以提高表示的精度。
2. IEEE 745 標(biāo)準(zhǔn)
IEEE 745 定義了在計算機中浮點數(shù)的表示及其運算的標(biāo)準(zhǔn),標(biāo)準(zhǔn)指定了兩種基本浮點格式:單精度和雙精度,兩種擴展浮點格式:單精度擴展和雙精度擴展。
浮點格式是一種數(shù)據(jù)結(jié)構(gòu),用于指定包含浮點數(shù)的字段、這些字段的布局及其算術(shù)解釋。浮點存儲格式指定如何將浮點格式存儲在內(nèi)存中,具體選擇哪種存儲格式由實現(xiàn)工具決定,JavaScript 采用的是 IEEE 745 雙精度浮點格式。
IEEE 浮點標(biāo)準(zhǔn)用 V = (?1)? × 2? × M 的形式來表示一個數(shù):
· 符號(sign)s 決定這個數(shù)是正數(shù) s = 0 還是負(fù)數(shù) s = 1。
· 指數(shù)(exponent)E 的作用是對浮點數(shù)的加權(quán),權(quán)重是 2 的 E 次冪。
· 尾數(shù)(significand)M是一個二進(jìn)制小數(shù)。
如下圖所示,表示浮點數(shù)的位劃分為三個字段:
· 一個符號位 s。
· k 位的指數(shù)字段 exp = e??1 ... e1e? 編碼指數(shù) E。
· n 位的小數(shù)字段 frac = f?1f?2 ... f??編碼尾數(shù) M。
圖中給出了兩種最常見的格式,32位的單精度格式:1 位符號位、k = 8 的指數(shù)字段、n = 23 的小數(shù)字段,64 位的雙精度格式:1 位符號位、k = 11 的指數(shù)字段、n= 52 的小數(shù)字段。
3. IEEE 浮點格式轉(zhuǎn)為十進(jìn)制數(shù)
浮點格式要形成最終表示的值 V= 2? × M,需要對各個字段作如下處理:
·? 指數(shù) E = e - Bias,e表示為 e??1 ... e1e?,Bias 是一個等于 2??1 - 1 的偏移量。
· 小數(shù)字段 frac = f?1f?2 ... f??,尾數(shù) M = 1 + frac。
另外還有兩種情況:
· 當(dāng)指數(shù)字段全為 0 時,指數(shù)值是1 - Bias,尾數(shù)值是 M = frac。
· 當(dāng)指數(shù)字段全為 1 時,小數(shù)字段全為 0 表示無窮,小數(shù)字段不等于 0 表示NaN。
下面以 8 位浮點格式為例介紹如何將其轉(zhuǎn)為十進(jìn)制數(shù)。
如:0 0110 110,其中有 k = 4 的指數(shù)字段和 n = 3 的小數(shù)字段,各個部分的處理如下:
· 偏移量 Bias = 2??1 - 1 = 7。
· 指數(shù)字段 e = 0 × 23 + 1 × 22 + 1 × 21 + 0 ×2? = 6。
· 指數(shù) E = 6 - 7 = -1。
· 小數(shù)字段 frac = 1 × 2?1 + 1 × 2?2 + 0 × 2?3 = 3??。
· 尾數(shù) M = 1 + 3?? = ???。
· 最終值:V = 2? × M = 2?1 × ??? = 1?? × ??? = ??? = 0.875。
上面是精度計算的一些背景知識,下面我們來解答前面提到的兩個問題:
一、為什么會出現(xiàn)精度的丟失?
表示方法限制了浮點數(shù)的范圍和精度,所以浮點運算只能近似的表示實數(shù)運算。
IEEE 浮點格式定義了 4 種不同的舍入方式:
· Round-to-even,向偶數(shù)舍入,將數(shù)字向上或向下舍入,使得結(jié)果的最低有效數(shù)字是偶數(shù),如以十進(jìn)制數(shù)為例:1.5 和 2.5 都將舍入為 2。
· Round-toward-zero,向零舍入,把正數(shù)向下舍入,負(fù)數(shù)向上舍入。
· Round-down,向下舍入,把正數(shù)、負(fù)數(shù)都向下舍入。
· Round-up,向上舍入,把正數(shù)、負(fù)數(shù)都向上舍入。
JavaScript 中的浮點數(shù)有兩種來源,由服務(wù)端返回的數(shù)據(jù)或者通過運算產(chǎn)生的結(jié)果,從服務(wù)端返回數(shù)據(jù)到前端展現(xiàn)會經(jīng)過下面幾個環(huán)節(jié):
在這個過程中,需要解決 JSON 解析丟失精度的問題、高精度浮點數(shù)運算的問題、高精度浮點數(shù)展示的問題。
在 JavaScript 中通常會用 number 數(shù)據(jù)類型來保存數(shù)值、進(jìn)行數(shù)值的運算,但由于 IEEE 浮點格式的限制,用 number 類型保存一個大浮點數(shù)時,精度會丟失。
const num = 106119.43448475052345678
// 106119.43448475053
?
同樣,我們常用的JSON.parse 方法解析 JSON 字符串時,大浮點數(shù)的精度也會丟失。
const data = JSON.parse('{"values":[106119.43448475052345678,755180144.3253138888456,3086.27072845812345678]}');
// {
//? ?values: [
//? ? ?106119.43448475053,
//? ? ?755180144.3253139,
//? ? ?3086.2707284581234
//? ?]
// }
二、如何解決精度丟失問題?
要確保從服務(wù)端獲取的大浮點數(shù)精度不丟失,就不能用 JSON.parse 方法來解析 HTTP Response Body 里的 JSON 字符串,也不能直接用 number 類型來保存數(shù)值。
解析 JSON 時可以把數(shù)值保存為 string 類型:
const data = {
? values: [
? ? '106119.43448475052345678',
? ? '755180144.3253138888456',
? ? '3086.27072845812345678'
? ]
};
?
JSON 解析可以用第 3 方庫,如:https://github.com/sidorares/json-bigint
要對高精度浮點數(shù)進(jìn)行運算,首先要將其轉(zhuǎn)為便于運算的結(jié)構(gòu),如:
// '106119.43448475052345678'
let?num = {
? // 數(shù)值拆成數(shù)組
? c: [106119, 43448475052345, 67800000000000],
? // 標(biāo)識數(shù)值的指數(shù)
? e: 5,
? // 標(biāo)識數(shù)值的正負(fù)
? s: 1
};
// '3086.27072845812345678'
let?num2 = {
? c: [3086, 27072845812345, 67800000000000],
? e: 3,
? s: 1
};
?
轉(zhuǎn)為如上結(jié)構(gòu)后,再對數(shù)組中的各段數(shù)值進(jìn)行運算。
高精度數(shù)值運算可以使用第 3 方庫,如:http://mikemcl.github.io/bignumber.js/
高精度浮點數(shù)在網(wǎng)頁中的展示有所不同,具體如下:
浮點數(shù)在頁面上的展示通常有兩種方式,創(chuàng)建為一個文本節(jié)點、通過 Canvas 或 SVG 畫成圖表。
創(chuàng)建為文本節(jié)點來展示沒有什么問題,如:
document.createTextNode('106119.43448475052345678');
// 或
let?div =document.createElement('div');
div.innerText = '106119.43448475052345678';
畫圖表通常會用到第 3 方庫,如:ECharts、G2 等,各種圖表的具體實現(xiàn)上會依賴數(shù)值的比較、四則運算等,目前 ECharts、G2 還沒有對大浮點數(shù)的支持。
看完上文是不是學(xué)到很多?
想要深入了解的小伙伴,歡迎來撩神策數(shù)據(jù)的技術(shù)小哥哥,各個身懷絕技哦!
PS:此篇文章就是技術(shù)小哥哥皮成的經(jīng)驗分享
與鳳凰同飛,必是俊鳥;與虎狼同行,必是猛獸!
來神策數(shù)據(jù),你不變優(yōu)秀,我輸一包辣條!
對,我們正在尋找優(yōu)秀的你!
快來加入我們吧!
熱招崗位
大數(shù)據(jù)前端工程師
?
JS 數(shù)據(jù)采集方向:
1、負(fù)責(zé)神策 JS SDK 的開發(fā),維護(hù),客戶支持;
2、負(fù)責(zé)前端相關(guān)數(shù)據(jù)采集方案的調(diào)研和開發(fā),比如微信小程序,支付寶等。
?
數(shù)據(jù)可視化方向:
1、負(fù)責(zé)數(shù)據(jù)分析產(chǎn)品的 Web 前端研發(fā);
2、與產(chǎn)品設(shè)計師一起,優(yōu)化整個產(chǎn)品的使用流程,為使用者提供更好的數(shù)據(jù)可視化效果;
3、負(fù)責(zé)前端新技術(shù)的探索與實踐。
我們的挑戰(zhàn):
1、單頁面復(fù)雜 Web 應(yīng)用,需要管理 10 萬行業(yè)務(wù)代碼,代碼量還在快速增長中;
2、與大量數(shù)據(jù)打交道,需要對數(shù)據(jù)業(yè)務(wù)有深層次的理解;
3、服務(wù)大量客戶,產(chǎn)品快速迭代的同時,要讓系統(tǒng)在健康的軌道上發(fā)展。
對工程師的要求:
1、熟練掌握 HTML/CSS/JavaScript 等前端基礎(chǔ)技術(shù);
2、能寫出高質(zhì)量的代碼,有良好的代碼風(fēng)格、了解各種設(shè)計模式;
3、React/Vue/Angular 技術(shù)棧至少掌握其中一種,對背后的設(shè)計思路應(yīng)該比較了解,讀源碼應(yīng)該沒什么困難;
4、對寫代碼之外的事情能熟練運用各種工程工具處理,對工具背后的工作原理應(yīng)該有一些了解;
5、10 萬行代碼在瀏覽器里運行,性能方面是個挑戰(zhàn),怎么分析、優(yōu)化性能應(yīng)該有一定的了解;
6、很好的業(yè)務(wù)理解能力,與大數(shù)據(jù)打交道,需要理解的不只是頁面上有哪些 UI 組件。
關(guān)于簡歷,我們想看到的:
1、做過的最牛的項目,用到了什么技術(shù)、實現(xiàn)了什么功能、有什么收獲。
2、寫過的最牛的代碼。
如果想用前端技術(shù)做一些有趣、有挑戰(zhàn)的事情,歡迎給我們簡歷!
如果沒有開發(fā)過復(fù)雜 Web 應(yīng)用,但對自己的學(xué)習(xí)能力足夠自信,歡迎給我們簡歷!
?劃重點?
【工作地點】北京
【應(yīng)聘方式】簡歷可發(fā)送至郵箱?
hr@sensorsdata.cn
?
Hr 小姐姐都很美哦!歡迎來撩~
更多崗位可在神策數(shù)據(jù)官網(wǎng)了解
參考資料:
·IEEE 754,https://en.wikipedia.org/wiki/IEEE_754
·Numerical Computation Guide,https://docs.oracle.com/cd/E19957-01/806-3568/ncgTOC.html
· 《深入理解計算機系統(tǒng)》
?!神策數(shù)據(jù)開“技術(shù)內(nèi)參”新欄目啦 !
有內(nèi)涵的人就該發(fā)光!
你有技術(shù)干貨,我有曝光渠道!
歡迎給我們投稿,好的文章不僅會在神策數(shù)據(jù)公眾號發(fā)布,也會在神策數(shù)據(jù)新媒體矩陣發(fā)布,讓你 blingbling!
投稿方式:
將文章發(fā)送郵箱,我們會在 1-2 個工作日給您反饋!
郵箱:wangyajun@sensorsdata.cn?
如郵箱未及時回復(fù)可加微信?wafree?聯(lián)系投稿~
總結(jié)
以上是生活随笔為你收集整理的技术内参 | 数据分析,如何解决精度丢失的问题?的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 捞月狗签约神策数据 数据赋能打造全球玩家
- 下一篇: 金融实战篇:最佳数据驱动之城商行