做者:小傅哥
博客:https://bugstack.cnhtml
沉澱、分享、成長,讓本身和他人都能有所收穫!😄java
數學離程序員有多近?
git
ifelse也好、for循環也罷,代碼能夠說就是對數學邏輯的具體實現。因此敲代碼的程序員幾乎就離不開數學,難易不一樣而已。程序員
那數學很差就寫不了代碼嗎😳?不,同樣能夠寫代碼,能夠寫出更多的CRUD
出來。那你不要總以爲是產品需求簡單因此你的實現過程才變成了增刪改查,每每也是由於你還不具有可擴展、易維護、高性能的代碼實現方案落地能力,才使得你小小年紀寫出了更多的CRUD
!算法
與一錐子買賣的小做坊相比,大廠和超級大廠更會注重數學能力。數據庫
2004年,在硅谷的交通動脈 101 公路上忽然出現一塊巨大的廣告牌,上面是一道數學題: {e 的連續數字中最早出現的 10 位質數}
.com。編程
廣告:這裏的 e 是數學常數,天然對數的底數,無限不循環小數。這道題的意思就是,找出 e 中最早出現的 10 位質數,而後能夠得出一個網址。進入這個網址會看到 Google 爲你出的第二道數學題,成功解鎖這步 Google 會告訴你,咱們或許是」志同道合「的人
,你能夠將簡歷發到這個郵箱,咱們一塊兒作點改變世界的事情。設計模式
計算 e 值能夠經過泰勒公式推導出來:e^x≈1 + x + x^2/2! + x^3/3! +……+ x^n/n! (1) 推導計算過程還包括埃拉托色尼篩選法(the Sieve of Eratosthenes)
、線性篩選法
的使用。感興趣的小夥伴能夠用代碼實現下。數組
業務提需求、產品定方案、研發作實現。
最終這個系統開發的怎麼樣是由三方共同決定的!微信
這裏的地基、磚頭、水電、格局,對應的就是,數據結構、算法邏輯、設計模式、系統架構。從下到上相互依賴、相互配合,只有這一層作好,下一層纔好作!
因此,研發在承接業務需求、實現產品方案的時候。壓根就不僅是在一個房子的三居或者四居格局裏,開始隨意碼磚。
沒有合理的數據結構、沒有優化的算法邏輯、沒有運用的設計模式,最終都會影響到整個系統架構變得臃腫不堪,調用混亂。在之後附加、迭代、新增的需求下,會讓整個系統問題不斷的放大,當你想用重構時,就有着千絲萬縷般調用關係。 重構就不如重寫了!
在《編程之美》一書中,有這樣一道題。求:1n中,1出現的次數。好比:110,1出現了兩次。
long startTime = System.currentTimeMillis(); int count = 0; for (int i = 1; i <= 10000000; i++) { String str = String.valueOf(i); for (int j = 0; j < str.length(); j++) { if (str.charAt(j) == 49) { count++; } } } System.out.println("1的個數:" + count); System.out.println("計算耗時:" + (System.currentTimeMillis() - startTime) + "毫秒");
使用 for 循環的實現過程很好理解,就是往死了循環。以後把循環到的數字按照字符串拆解,判斷每一位是否是數字,是就+1。這個過程很簡單,可是時間複雜很高。
如圖 20-3 所示,其實咱們能發現這個1的個數在100、1000、10000中是有規則的循環出現的。十一、十二、1三、14或者2一、3一、4一、51,以及單個的1出現。最終能夠得出通用公式:abcd...=(abc+1)*1+(ab+1)*10+(a+1)*100+(1)*1000...
,abcd表明位數。另外在實現的過程還須要考慮好比不足100等狀況,例如9八、1232等。
實現過程
long startTime = System.currentTimeMillis(); int num = 10000000, saveNum = 1, countNum = 0, lastNum = 0; int copyNum = num; while (num != 0) { lastNum = num % 10; num /= 10; if (lastNum == 0) { // 若是是0那麼正好是少了一次因此num不加1了 countNum += num * saveNum; } else if (lastNum == 1) { // 若是是1說明當前數內少了一次因此num不加1,並且當前1所在位置 // 有1的個數,就是去除當前1最高位,剩下位數,的個數。 countNum += num * saveNum + copyNum % saveNum + 1; } else { // 若是非1非0.直接用公式計算 // abcd...=(abc+1)*1+(ab+1)*10+(a+1)*100+(1)*1000... countNum += (num + 1) * saveNum; } saveNum *= 10; } System.out.println("1的個數:" + countNum); System.out.println("計算耗時:" + (System.currentTimeMillis() - startTime) + "毫秒");
在《編程之美》一書中還不僅這一種算法,感興趣的小夥伴能夠查閱。但本身折騰實現後的興奮感更強哦!
按照兩種不一樣方式的實現邏輯,咱們來計算1000、10000、10000到一個億,求1出現的次數,看看兩種方式的耗時曲線。
那麼,你的代碼中是否也有相似的地方。若是使用算法邏輯配合適合的數據結構,是否能夠替代一些for循環的計算方式,來使整個實現過程的時間複雜度下降。
在 Java 的 JDK 實現中有不少數學知識的運用,包括數組、鏈表、紅黑樹的數據結構以及相應的實現類ArrayList、Linkedlist、HashMap等。當你深刻的瞭解這些類的實現後,會發現它們其實就是使用代碼來實現數學邏輯而已。就像你使用數學公式來計算數學題同樣
接下來小傅哥就給你介紹幾個隱藏在咱們代碼中的數學知識。
未使用擾動函數
已使用擾動函數
擾動函數公式
static final int hash(Object key) { int h; return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); }
f(k) = ((k * 2654435769) >> X) << Y對於常見的32位整數而言,也就是 f(k) = (k * 2654435769) >> 28
除法散列法
、平方散列法
、隨機數法
等。// Initializes mt[N] with a simple integer seed. This method is // required as part of the Mersenne Twister algorithm but need // not be made public. private final void setSeed(int seed) { // Annoying runtime check for initialisation of internal data // caused by java.util.Random invoking setSeed() during init. // This is unavoidable because no fields in our instance will // have been initialised at this point, not even if the code // were placed at the declaration of the member variable. if (mt == null) mt = new int[N]; // ---- Begin Mersenne Twister Algorithm ---- mt[0] = seed; for (mti = 1; mti < N; mti++) { mt[mti] = (MAGIC_FACTOR1 * (mt[mti-1] ^ (mt[mti-1] >>> 30)) + mti); } // ---- End Mersenne Twister Algorithm ---- }
梅森旋轉算法(Mersenne twister)是一個僞隨機數發生算法。由松本真和西村拓士在1997年開發,基於有限二進制字段上的矩陣線性遞歸。能夠快速產生高質量的僞隨機數,修正了古典隨機數發生算法的不少缺陷。 最爲普遍使用Mersenne Twister的一種變體是MT19937,能夠產生32位整數序列。
與接觸到一個有難度的知識點學起來辛苦相比,是本身不知道本身不會什麼!就像上學時候老師說,你不會的就問我。我不會啥?我從哪問?同樣同樣的!
代碼是對數學邏輯的實現,簡單的邏輯調用關係是很容易看明白的。但還有那部分你可能不知道的數學邏輯時,就很難看懂了。好比:擾動函數、負載因子、斐波那契(Fibonacci)等,這些知識點的學習都須要對數學知識進行驗證,不然也就學個概念,背個理論。
書到用時方恨少,在下仍是個寶寶!
那若是你想深刻的學習下程序員應該會的數學,推薦給你一位科技博主 Jeremy Kun 花了4年時間,寫成一本書 《程序員數學入門》。
這本書爲程序員提供了大量精簡後數學知識,包括:多項式、集合、圖論、羣論、微積分和線性代數等。同時在wiki部分還包括了抽象代數、離散數學、傅里葉分析和拓撲學等。
做者表示,若是你本科學過一些數學知識,那麼本書仍是挺適合你的,不會有什麼難度。書中的前三章是基礎數學內容,日後的難度依次遞增。
程序員數學
,下載這本書知識的路上是發現知識的快樂,還學會知識的成就感,不斷的促使你前行
。