摘要:前言在數(shù)據(jù)敏感的業(yè)務(wù)場(chǎng)景中,常常會(huì)碰到數(shù)據(jù)精度問(wèn)題,尤其在金額顯示占比統(tǒng)計(jì)等地方,該問(wèn)題尤為顯著。計(jì)算機(jī)原理真香數(shù)值的精度問(wèn)題,其實(shí)是非?;A(chǔ)的計(jì)算機(jī)原理知識(shí)。
前言在數(shù)據(jù)敏感的業(yè)務(wù)場(chǎng)景中,常常會(huì)碰到數(shù)據(jù)精度問(wèn)題,尤其在金額顯示、占比統(tǒng)計(jì)等地方,該問(wèn)題尤為顯著。由于數(shù)據(jù)的每一位有效數(shù)字都包含真實(shí)的業(yè)務(wù)語(yǔ)義,一點(diǎn)點(diǎn)偏差甚至可能影響業(yè)務(wù)決策,這讓問(wèn)題的嚴(yán)重性上升了幾個(gè)階梯。
那,什么是精度丟失?一言以概之,凡是在運(yùn)行過(guò)程中,導(dǎo)致數(shù)值存在不可逆轉(zhuǎn)換時(shí),就是精度丟失。
諸如:
人均交易額、占比這類(lèi)計(jì)算得出的除法獲得的指標(biāo)(分子/分母)時(shí),如果盲目的直接從該結(jié)果去推算分子數(shù)值時(shí),很可能就存在精度丟失
浮點(diǎn)數(shù)計(jì)算結(jié)果,會(huì)出現(xiàn)很長(zhǎng)尾的小數(shù)
這兩種廣義上來(lái)說(shuō)都是精度丟失,但第一種情況可以通過(guò)更改技術(shù)方案等方式進(jìn)行規(guī)避。更多時(shí)候,所謂的精度問(wèn)題,單指第二類(lèi)問(wèn)題。而面對(duì)這類(lèi)問(wèn)題時(shí),如果沒(méi)有掌握原理,往往會(huì)一知半解,對(duì)結(jié)論印象不深,再次碰到問(wèn)題只能一查再查。
計(jì)算機(jī)原理真香數(shù)值的精度問(wèn)題,其實(shí)是非?;A(chǔ)的計(jì)算機(jī)原理知識(shí)。通常,js的系統(tǒng)知識(shí)書(shū)籍(基礎(chǔ)類(lèi)型章節(jié))一般也會(huì)提到,但像我這樣的非科班前端開(kāi)發(fā),往往在這方面的知識(shí)儲(chǔ)備非常薄弱;而且,即使學(xué)習(xí)過(guò)了,也會(huì)因?yàn)榈谝淮螌W(xué)習(xí)時(shí)沒(méi)體感,沒(méi)有實(shí)際場(chǎng)景去強(qiáng)化認(rèn)知,掌握的也不深刻。
所以,在后續(xù)的業(yè)務(wù)開(kāi)發(fā)中,有必要重新整理下遇到的問(wèn)題,從遇到的問(wèn)題出發(fā),追根溯源,才能更深刻地掌握知識(shí)點(diǎn)。
真實(shí)的Number(本章節(jié)為基礎(chǔ)的規(guī)范介紹,有助于加深認(rèn)知,非必要知識(shí),尤其是存儲(chǔ)形式,大部分問(wèn)題的解答只需有概念即可。)
有別于其他語(yǔ)言會(huì)出現(xiàn)各類(lèi)int、uint、float,JS語(yǔ)言只有一種數(shù)值類(lèi)型——Number,它的背后是標(biāo)準(zhǔn)的雙精度浮點(diǎn)數(shù)實(shí)現(xiàn)(其他語(yǔ)言一般稱(chēng)該類(lèi)型為double或float64),這也就意味著,前端所有出現(xiàn)的數(shù)值,其實(shí)背后都是小數(shù)。
看一下雙精度浮點(diǎn)數(shù)的內(nèi)存模型(這幅維基百科的示意圖真是每篇精度文章都會(huì)引用~):
存儲(chǔ)形式
這篇文章介紹了一個(gè)非常簡(jiǎn)單的轉(zhuǎn)換方式,拿一個(gè)數(shù)值實(shí)際體驗(yàn)一下過(guò)程,例如34.1:
第一步,取整數(shù)部分——34,通過(guò)除2取余數(shù):
計(jì)算過(guò)程 | 結(jié)果 | 余數(shù) |
---|---|---|
34/2 | 17 | 0 |
17/2 | 8 | 1 |
8/2 | 4 | 0 |
4/2 | 2 | 0 |
2/2 | 1 | 0 |
1/2 | 0 | 1 |
第二步,取小數(shù)部分——0.1,通過(guò)乘2取整數(shù)。如果結(jié)果大于1,則取1,否則取0:
計(jì)算過(guò)程 | 結(jié)果 | 整數(shù) |
---|---|---|
0.1*2 | 0.2 | 0 |
0.2*2 | 0.4 | 0 |
0.4*2 | 0.8 | 0 |
0.8*2 | 1.6 | 1 |
0.6*2 | 1.2 | 1 |
0.2*2 | 0.4 | 0 |
... | ... | ... |
第三步,拼接結(jié)果,整數(shù)部分結(jié)果是從下往上取,小數(shù)部分則是從上往下取。結(jié)果為:(34.1)10 = (100010.0_0011_0011_0011...)2。
ps:為了閱讀清晰,使用下劃線分隔符~該特性將在Chrome75到來(lái),諸如Rust已經(jīng)具備
第四步,轉(zhuǎn)換為科學(xué)計(jì)數(shù)法(二進(jìn)制版),(34.1)10 = 1.00010_0_0011_0011... * 2(5)10 。到此,已經(jīng)可以獲取到公式中各個(gè)值所對(duì)應(yīng)的結(jié)果了:
S = 0
E = (5 + 1023)10 = (100_0000_0100)2
M = (00010_0_0011_0011...)2
最終的34.1的內(nèi)存存儲(chǔ)為:0? 100_0000_0100? 00010_0_0011_0011_0011_0011_0011_0011_0011_0011_0011_00 11_0011_01。(我反正是瞎了)
對(duì)于這個(gè)結(jié)果,還需要幾點(diǎn)補(bǔ)充說(shuō)明:
指數(shù)部分有11位bit。使用無(wú)符號(hào)表示,可以表示范圍0~2047,其中0和2047為非規(guī)約形式,有特殊意義(詳見(jiàn)wiki,不做展開(kāi)了),那剩余的范圍是1~2046;如果使用帶符號(hào)表示,可以表示范圍-1024~1023。因?yàn)閷?shí)際指數(shù)是可以存在負(fù)值的,為了避免使用符號(hào)表示法,就加入了這個(gè)偏移量。
至于,為什么不使用符號(hào)?我沒(méi)什么太深刻的體感。不過(guò)可以肯定的是,目的一定是為了后續(xù)的計(jì)算處理方便。比如:如果無(wú)符號(hào),可以直接比較大???
這是因?yàn)?,既然?shù)值一定可以表示成科學(xué)計(jì)數(shù)法,那尾數(shù)M的整數(shù)部分必然是1。
為什么?如果實(shí)在想不明白,可以參考十進(jìn)制的科學(xué)計(jì)數(shù)法,整數(shù)部分一定是1~9,因?yàn)橐坏┏^(guò)9,就會(huì)歸入指數(shù),即,整數(shù)部分為1~【進(jìn)制-1】。那在二進(jìn)制的科學(xué)計(jì)數(shù)法中,整數(shù)部分為1~1,則必然是1。
此外,這里還有另一點(diǎn)好處,通過(guò)省略整數(shù)部分,這個(gè)“1”就不需要占用存儲(chǔ)了,相對(duì)的,小數(shù)部分可以多一位有效數(shù)字。
正如上例中的34.1,它的尾數(shù)部分就是無(wú)限循環(huán),如果超出了存儲(chǔ)位數(shù),則勢(shì)必要進(jìn)行舍入。
實(shí)際上,存在多種舍入規(guī)則:
舍入到最接近
朝+∞方向舍入
朝-∞方向舍入
朝0方向舍入
也不做展開(kāi)了,具體可以繼續(xù)查閱wiki。默認(rèn)理解下,“0舍1入”的規(guī)則夠用了。
舉一反三Number類(lèi)上的一個(gè)靜態(tài)屬性,值為9007199254740991。這個(gè)數(shù)是怎么來(lái)的呢?
因?yàn)镹umber的尾數(shù)有53位,理論上能表示的、精確的最大整數(shù)即為2-1,這也正是MAX_SAFE_INTEGER。超過(guò)這個(gè)值的數(shù)值,因?yàn)橛行?shù)字有限,Number已經(jīng)無(wú)法精確表示了。
然而指數(shù)部分最大值是1023,所以理論上Number能表示的最大值應(yīng)該至少達(dá)到2才對(duì),那這個(gè)區(qū)間(2~2)的如何存儲(chǔ)呢?我沒(méi)有太深入思考,原理上應(yīng)該也是通過(guò)舍入規(guī)則去理解,不過(guò)還是不展開(kāi)了,留個(gè)坑位~
題外話:
很多面試題里都包含了大整數(shù)的考點(diǎn)??嫉氖莾商帲谝稽c(diǎn)是,是否意識(shí)到了面試題中存在大整數(shù)問(wèn)題;第二點(diǎn)是,如何用程序模擬手算過(guò)程。
不過(guò)我比較好奇的是,假如面試者使用了BigInt來(lái)完成大整數(shù)的四則運(yùn)算(跳過(guò)第二個(gè)考點(diǎn))是不是也算合格?【笑
同樣是Number類(lèi)上的一個(gè)靜態(tài)屬性,值為2.220446049250313e-16。這個(gè)數(shù)又是怎么來(lái)的?
同樣和尾數(shù)相關(guān),理論上能表示的最小尾數(shù)是1.00000000_00000000_00000000_00000000_00000000_00000000_0001,也就是EPSILON。
一般來(lái)說(shuō),double類(lèi)型的有效位數(shù),結(jié)論是16位。不過(guò),目前我還沒(méi)看到非常嚴(yán)謹(jǐn)?shù)恼f(shuō)明過(guò)程,現(xiàn)有的解釋方式略作搬運(yùn):
MAX_SAFE_INTEGER是9007199254740991,它的位數(shù)就是16
EPSILON它能精確到小數(shù)點(diǎn)后15位,再加上整數(shù)位,所以,有效位數(shù)是16
lint規(guī)則中一般是不建議在JS代碼中使用位運(yùn)算的。
第一點(diǎn)是,不便于維護(hù),考慮到前端開(kāi)發(fā)普遍對(duì)位運(yùn)算不感冒;
第二點(diǎn)是,如兩次取反(~~3.11)、或0(3.11 | 0)這種取整操作,其背后,實(shí)際上是將64位的雙精度浮點(diǎn)數(shù)轉(zhuǎn)成了32位整數(shù)。如果對(duì)此沒(méi)有明確的認(rèn)知,能確保程序運(yùn)行時(shí)的入?yún)⒈囟ㄊ?2位整數(shù)范圍內(nèi)的話,就很容易埋坑,不如老老實(shí)實(shí)的使用Math.floor或Math.round。
const n = 2**32 + 0.1 // 4294967296.1
~~n // 期望是2^32,但其實(shí)結(jié)果是0
Math.floor(n) // 符合預(yù)期
Number的計(jì)算
明白了真實(shí)的Number,很容易就理解了——由于一個(gè)小數(shù)無(wú)法用二進(jìn)制精準(zhǔn)表示,勢(shì)必存在精度丟失,也就很自然地會(huì)出現(xiàn)諸如經(jīng)典的“0.1+0.2 ≠ 0.3”問(wèn)題。但與此同時(shí),我產(chǎn)生了一個(gè)疑問(wèn),兩個(gè)精度丟失的純小數(shù)是否能得出一個(gè)精準(zhǔn)表示的數(shù)值?
(由于雙精度浮點(diǎn)數(shù)實(shí)在位數(shù)太多了。。。寫(xiě)得累,下面都使用單精度浮點(diǎn)數(shù)表意,雙精度的情況可以同理類(lèi)推。)
嚴(yán)格來(lái)說(shuō),浮點(diǎn)數(shù)計(jì)算需要經(jīng)過(guò):對(duì)階、尾數(shù)求和、規(guī)約化、舍入、溢出判斷(詳細(xì)內(nèi)容,可以參閱此文)。如果嚴(yán)格按照步驟進(jìn)行,有些過(guò)于死板,而且其中有更多的概念需要消化,這里僅僅是為了加深體感,所以使用更“小學(xué)”的方式來(lái)解決這個(gè)問(wèn)題。
在進(jìn)行具體計(jì)算前,需要先掌握:
如何將十進(jìn)制轉(zhuǎn)為二進(jìn)制,上一章介紹過(guò)了
有效數(shù)字位數(shù),單精度浮點(diǎn)數(shù)尾數(shù)部分為23位,相應(yīng)的,能表示的有效位數(shù)為24位(為什么?),上一章也介紹過(guò)了
手算加法
0.1 + 0.4將0.1和0.4轉(zhuǎn)為二進(jìn)制(不需要轉(zhuǎn)為科學(xué)計(jì)數(shù)法,即可跳過(guò)對(duì)階步驟),結(jié)果是:
0.1 = 0.0_0011_0011_0011_0011_0011_0011_01,保留24位有效數(shù)字,根據(jù)“0舍1入”進(jìn)位
0.4 = 0.0_1100_1100_1100_1100_1100_1101,保留24位有效數(shù)字,根據(jù)“0舍1入”進(jìn)位
可以看到,0.1和0.4都是存在進(jìn)位的,它的存儲(chǔ)值比真實(shí)值都要大,那兩個(gè)比真實(shí)值大的數(shù)的是如何恰好相加得出0.5的呢?
核心關(guān)鍵點(diǎn),其實(shí)在于這個(gè)**“有效位數(shù)”**,我們手算一下,把這兩個(gè)值直接相加,現(xiàn)在位數(shù)已經(jīng)對(duì)齊了:
0.0_0011_0011_0011_0011_0011_0011_01 + 0.0_1100_1100_1100_1100_1100_1101 ----------------------------------------------- 0.1_0000_0000_0000_0000_0000_0000_(01)
0.1就是0.5,實(shí)在是太巧了!誤差正好被排除在有效位數(shù)之外!也就是,兩個(gè)丟失精度的數(shù)值計(jì)算后恰好精度復(fù)原了。
好奇心如我,覺(jué)得這里應(yīng)該是可以用數(shù)學(xué)方式去證明,無(wú)整數(shù)部分的小數(shù)計(jì)算,誤差一定會(huì)控制在相對(duì)小的范圍之內(nèi)的。否則,如果按照常規(guī)理解,隨著計(jì)算進(jìn)行,誤差會(huì)無(wú)休止的膨脹下去。
當(dāng)然,這種證明過(guò)程肯定很專(zhuān)業(yè),估計(jì)真展示在我面前,我也看不懂。我等普通吃瓜開(kāi)發(fā),還是只管喊666就成了~
0.1 * 10掌握了加減法,就自然會(huì)對(duì)乘法產(chǎn)生新的疑惑(主要是解決精度問(wèn)題中很常見(jiàn)的辦法是轉(zhuǎn)為整數(shù))。既然,0.1是無(wú)法精確表示的,而1和10作為整數(shù)又是可以精確表示的,那這里的結(jié)果“1”是精確的“1”,還是一個(gè)非常近似的小數(shù)?如果是精確的,丟失精度的小數(shù)是如何轉(zhuǎn)為精確的整數(shù)的呢?
浮點(diǎn)數(shù)的乘法有特別算法(Booth算法)可以細(xì)講的,不過(guò)在此也不做具體展開(kāi)。
基本原理上來(lái)說(shuō),就是將乘法簡(jiǎn)化為“移位 + 加減法”。在本例中,10可以拆為2 + 2,繼續(xù)手算:
0.1 * 10 = 0.1 * 2^3 + 0.1 * 2 0.1100_1100_1100_1100_1100_1101 + 0.0011_0011_0011_0011_0011_0011_01 --------------------------------------------------- 1.0000_0000_0000_0000_0000_0000_(01)
是不是又一次感慨世界的奇妙?和上一例結(jié)果一樣,誤差再一次被命運(yùn)排除在有效位數(shù)之外,amazing~~
不過(guò),需要注意的是,這兩個(gè)示例都限定在了無(wú)整數(shù)部分的小數(shù)計(jì)算(也可能是整數(shù)部分需要滿足什么條件才可以)。如果整數(shù)部分存在有效數(shù)字,會(huì)不同程度的擠壓小數(shù)部分可用的尾數(shù)有效位數(shù),就有可能導(dǎo)致無(wú)法出現(xiàn)這些神奇結(jié)果了。
/10 和 *0.1 的區(qū)別這個(gè)區(qū)別可以簡(jiǎn)單的進(jìn)行求證。只需提高結(jié)果的精度表示,就可以看到差異:
(6 / 10).toPrecision(17) // "0.59999999999999998"
(6 * 0.1).toPrecision(17) // "0.60000000000000009"
究其原因,0.1是無(wú)法精確表示的,而10是可以精確表示的,所以和一個(gè)可以準(zhǔn)確表示的數(shù)進(jìn)行計(jì)算,勢(shì)必精度會(huì)高于和無(wú)法準(zhǔn)確表示的數(shù)進(jìn)行計(jì)算。
這就是典型的誤差累計(jì),當(dāng)結(jié)果是無(wú)法精確表示的時(shí)候,之前那神奇的誤差清除似乎就沒(méi)那么靈驗(yàn)了。所以,如果有必要,計(jì)算過(guò)程中,可以有意識(shí)的盡量使用整數(shù)。
解決方式 toFixed這是最基礎(chǔ)的解法。不過(guò)需要注意的是,當(dāng)尾數(shù)是5的時(shí)候,它的結(jié)果往往不符合預(yù)期。
這篇文章里,舉了個(gè)例子:
(1.005).toFixed(2) // 結(jié)果是1.00,而不是1.01
// 文中給出的解釋是將該數(shù)值進(jìn)行更高精度展示,確實(shí)該數(shù)值的四舍五入確實(shí)是1.00
(1.005).toPrecision(17) // "1.0049999999999999"
然而,評(píng)論中,被人錘了:
(1.105).toPrecision(17) // "1.1050000000000000"
(1.105).toFixed(2) // 結(jié)果是1.10
這是為什么?
思路上沒(méi)有問(wèn)題,只是,精度還不夠。如果我們按照規(guī)范理解toFixed,那核心在于這一步驟:
Let?n?be an integer for which the exact mathematical value of?n?÷ 10?–?x?is as close to zero as possible. If there are two such?n, pick the larger?n.
套用在這個(gè)例子中就是:
n / 100 - 1.105 // n為整數(shù),盡可能讓結(jié)果趨于0,最終計(jì)算誤差取17位精度
n = 110, // -0.0049999999999998934
n = 105, // 0.0050000000000001155
確實(shí)n = 110時(shí),結(jié)果更接近0,也就是toFixed的結(jié)果是1.10。
當(dāng)然,使用取高精度方式去求解也未嘗不可,只是,實(shí)際規(guī)范過(guò)程中,可以注意到,這一步計(jì)算會(huì)把整數(shù)部分以及小數(shù)點(diǎn)后的n(toFixed參數(shù))位全部歸0,所以如果需要正確的觀測(cè)當(dāng)前值,需要toPrecision(17 + n),也就是:
(1.105).toPrecision(19) // 1.104999999999999982
// 也就可以正確推出toFixed(2)的結(jié)果是1.10了
Math.round
這里補(bǔ)充一點(diǎn),一般場(chǎng)景中,如果想獲取四舍五入的整數(shù),往往會(huì)使用Math.round。但需要注意,這里依然有不符合預(yù)期的結(jié)果:
Math.round(1.005 * 100) / 100 // 結(jié)果是1,而不是期望的1.1
Math.round(-0.5) // 結(jié)果是0,而不是期望的-1
第一例的問(wèn)題其實(shí)是1.005無(wú)法轉(zhuǎn)為精確的整數(shù)導(dǎo)致的:1.005 * 1000 =?1004.9999999999999。所以只需要額外的多進(jìn)行一次轉(zhuǎn)換即可。
第二例的問(wèn)題其實(shí)是符合規(guī)范的,Math.round的結(jié)果是取更靠近+∞方向,而不是常規(guī)理解的遠(yuǎn)離0,所以碰到負(fù)數(shù),更保險(xiǎn)的做法應(yīng)該是使用絕對(duì)值再加符號(hào)位。
toPrecision上文提過(guò)雙精度浮點(diǎn)數(shù)能精確表示的位數(shù)是16位。如果toFixed使用時(shí)沒(méi)有注意整數(shù)部分,也會(huì)導(dǎo)致預(yù)期之外的錯(cuò)誤:
(1234123412341234.3).toFixed(2) // 1234123412341234.25
既然toFixed有種種問(wèn)題,而Number本身能達(dá)到的精度是16位,那其實(shí),數(shù)值運(yùn)算后的最終結(jié)果只要進(jìn)行Number.parseFloat(num.toPrecision(16))處理即可。
轉(zhuǎn)整數(shù)計(jì)算toPrecision可以避免絕大部分的小數(shù)點(diǎn)位數(shù)過(guò)長(zhǎng)的問(wèn)題。但,這可能導(dǎo)致結(jié)果和業(yè)務(wù)輸入的位數(shù)不一致,例如:
add(0.11, 0.19) => "0.30"
add(0.11, 0.100) => "0.210"
要解決這類(lèi)問(wèn)題,一般需要轉(zhuǎn)整數(shù)計(jì)算,不僅可以保證精度,也能輸出符合業(yè)務(wù)預(yù)期的位數(shù)。這也是絕大部分輕量庫(kù)的方案,基本原理是:
求出入?yún)⒌淖畲笪粩?shù)
轉(zhuǎn)為整數(shù)計(jì)算
最后輸出結(jié)果時(shí)再除去最大位數(shù)
當(dāng)然,這種方案的缺陷是,過(guò)程中一般無(wú)法顧及超出范圍的大數(shù)。
類(lèi)庫(kù)一步步了解了各種場(chǎng)景下出現(xiàn)的問(wèn)題,這時(shí)候再去選擇類(lèi)庫(kù),就有底氣的多,畢竟對(duì)于各種問(wèn)題的解決已初步具備思路,不會(huì)只停留在知其然而不知其所以然的境界。而使用成熟類(lèi)庫(kù)的好處是,它考慮的邊界條件更多、邏輯更完備,運(yùn)行時(shí)的穩(wěn)定性更高。
我列舉幾個(gè)類(lèi)庫(kù),不過(guò)使用不深,就請(qǐng)自行查閱啦~
Mathjs
BigNumber.js
Decimal.js(同一位大師)
Big.js(我不知道這位大師的三個(gè)庫(kù)具體區(qū)別是什么。。。)
number-precision,輕量級(jí)方案
Binary numbers – floating point conversion
JavaScript 浮點(diǎn)數(shù)陷阱及解法
如何避開(kāi)JavaScript浮點(diǎn)數(shù)計(jì)算精度問(wèn)題
IEEE 754
從0.1+0.2=0.30000000000000004再看JS中的Number類(lèi)型
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/7260.html
摘要:浮點(diǎn)數(shù)類(lèi)型包括單精度浮點(diǎn)數(shù)和雙精度浮點(diǎn)數(shù)。小結(jié)通過(guò)浮點(diǎn)數(shù)精度的問(wèn)題,了解到浮點(diǎn)數(shù)的小數(shù)用二進(jìn)制的表示。以后,在使用浮點(diǎn)數(shù)運(yùn)算的時(shí)候,一定要慎之又慎,細(xì)節(jié)決定成敗。 概述 記錄下,工作中遇到的坑 ... 關(guān)于 PHP 浮點(diǎn)數(shù)運(yùn)算,特別是金融行業(yè)、電子商務(wù)訂單管理、數(shù)據(jù)報(bào)表等相關(guān)業(yè)務(wù),利用浮點(diǎn)數(shù)進(jìn)行加減乘除時(shí),稍不留神運(yùn)算結(jié)果就會(huì)出現(xiàn)偏差,輕則損失幾十萬(wàn),重則會(huì)有信譽(yù)損失,甚至吃上官司,我...
摘要:關(guān)于芯片的選型,還是其他芯片的選型,那都不是隨隨便便就說(shuō)了算得。芯片成本參差不齊,選的好直接起飛,選的不好,直接破產(chǎn)。 關(guān)于ADC芯片的選型,還是其他芯片的選型,那...
摘要:輾轉(zhuǎn)流傳出班車(chē)手冊(cè)后發(fā)現(xiàn)搜索實(shí)在是太不方便了,于是有了一個(gè)主義,想做一個(gè)可以搜索房子地址,找出附近班車(chē)點(diǎn)類(lèi)似大眾點(diǎn)評(píng)的定位搜索附近餐館的功能。 起因 七月份要去某廠報(bào)道了,異地租房的時(shí)候發(fā)現(xiàn)想租一個(gè)有公司班車(chē)的地方,卻不知道哪里有班車(chē)。輾轉(zhuǎn)流傳出班車(chē)手冊(cè)后發(fā)現(xiàn)搜索實(shí)在是太不方便了,于是有了一個(gè)主義,想做一個(gè)可以搜索房子地址,找出附近班車(chē)點(diǎn)(類(lèi)似大眾點(diǎn)評(píng)的定位搜索附近餐館的功能)。現(xiàn)在做...
閱讀 1996·2021-09-09 09:33
閱讀 1118·2019-08-30 15:43
閱讀 2672·2019-08-30 13:45
閱讀 3313·2019-08-29 11:00
閱讀 863·2019-08-26 14:01
閱讀 3576·2019-08-26 13:24
閱讀 487·2019-08-26 11:56
閱讀 2696·2019-08-26 10:27