今天的每日一題比較……奇特。
實現 int sqrt(int x) 函式。我直接貼我在力扣寫的第一次題解:計算並返回 x 的平方根,其中 x 是非負整數。
由於返回型別是整數,結果只保留整數的部分,小數部分將被捨去。
示例 1:
輸入: 4 輸出: 2 示例 2:
輸入: 8 輸出: 2 說明: 8 的平方根是 2.82842…,
由於返回型別是整數,小數部分將被捨去。
emmmmmmm,算上讀題目我只寫了1min不到……大汗淋漓
int
mysqrt
(int x)
int
invsqrt
(float x)
intmysqrt
(int x)
執行結果:雖然可能有人看不太懂這段**,但是沒關係,能過就行。而且執行效率依然雙百。分析程式之前,我們必須解釋一下float資料在計算機裡的表示方式。一般而言,乙個float資料 x 共32個bit,和int資料一樣。其中前23位為有效數字 m_x ,後面接著乙個8位資料 e_x 表示指數,最後一位表示符號,由於這裡被開方的數總是大於0,所以我們暫不考慮最後乙個符號位。此時不過效率不如庫函式,偶爾會花4ms。提交三次左右就能看見雙百的結果。
效率算是最棒的了。思想是快速地蒙出乙個平方根的倒數,然後用牛頓迭代法快速逼近取值。效率很高。
x=1.m_x 2^
如果我們把計算機內的浮點數 x 看做乙個整數 i_x ,那麼
i_x = 2^e_x+m_x
現在開始逐步分析函式。這個函式的主體有四個語句,分別的功能是:
int i = (int)&x; 這條語句把 x 轉成 i=i_x 。
i = 0x5f3759df - (i>>1); 這條語句從 i_x 計算 i_} 。
y = (float)&i; 這條語句將 i_} 轉換為 1/\sqrt 。
y = y*(1.5f - xhalfyy); 這時候的y是近似解;此步就是經典的牛頓迭代法。迭代次數越多越準確。
關鍵是第二步 i = 0x5f3759df - (i>>1); 這條語句從 i_x 計算 i_} ,原理:
令 y=1/\sqrt ,用 x=(1+m_x)2^ 和 y=(1+m_y)2^ 帶入之後兩邊取對數,再利用近似表示 \log_2(1+z)\sim z+\delta ,算一算就得到
i_y = \frac(127-\delta)2^-i_x/2
若取 \delta=0.0450465679168701171875 , \frac(127-\delta)2^ 就是程式裡所用的常量0x5f3759df。至於為何選擇這個 \delta ,則應該是曲線擬合實驗的結果。
部分內容**:
LeetCode 簡單 69 x 的平方根
實現 int sqrt int x 函式。計算並返回 x 的平方根,其中 x 是非負整數。由於返回型別是整數,結果只保留整數的部分,小數部分將被捨去。示例 1 輸入 4 輸出 2 示例 2 輸入 8 輸出 2 說明 8 的平方根是 2.82842 由於返回型別是整數,小數部分將被捨去。class s...
69 x的平方根
一 題目 實現int sqrt int x 函式。計算並返回 x 的平方根,其中 x 是非負整數。由於返回型別是整數,結果只保留整數的部分,小數部分將被捨去。示例 1 輸入 4輸出 2示例 2 輸入 8輸出 2說明 8 的平方根是 2.82842.由於返回型別是整數,小數部分將被捨去。二 思路 採用...
69 x的平方根
題目描述 實現int sqrt int x 函式。計算並返回x的平方根,其中x 是非負整數。由於返回型別是整數,結果只保留整數的部分,小數部分將被捨去。示例 1 輸入 4 輸出 2 示例 2 輸入 8 輸出 2 說明 8 的平方根是 2.82842 由於返回型別是整數,小數部分將被捨去。知識點 二分...