淺談 BigInteger.Sqrt 方法
我們知道 .NET Framework 4 中已經有了 System.Numerics.BigInteger 結構。但是該 BigInteger 結構中沒有 Sqrt 方法。那麼就讓我們自己來寫一個吧:
01: using System; 02: using System.Numerics; 03: 04: namespace Skyiv 05: { 06: public static class Extensions 07: { 08: public static BigInteger Sqrt(this BigInteger x) 09: { 10: if (x.Sign < 0) throw new ArgumentOutOfRangeException("x", "must greater than 0"); 11: BigInteger low, high; 12: GetLowAndHigh(x, out low, out high); 13: var mid = low; 14: var cmp = 0; 15: while (low.CompareTo(high) <= 0) 16: { 17: mid = (low + high) / 2; 18: cmp = (mid * mid).CompareTo(x); 19: if (cmp < 0) low = mid + 1; 20: else if (cmp > 0) high = mid + (-1); 21: else return mid; 22: } 23: if (cmp > 0) mid--; 24: return mid; 25: } 26: 27: static void GetLowAndHigh(BigInteger x, out BigInteger low, out BigInteger high) 28: { 29: var n = x.ToByteArray().Length; 30: if (n < 2) 31: { 32: low = 0; 33: high = x; 34: return; 35: } 36: var bs = new byte[n / 2 + 1]; 37: var k = bs.Length - 2; 38: if (n % 2 == 0) 39: { 40: bs[k] = 0x0B; 41: low = new BigInteger(bs); 42: bs[k] = 0xB6; 43: high = new BigInteger(bs); 44: } 45: else 46: { 47: bs[k] = 0xB5; 48: low = new BigInteger(bs); 49: bs[k] = 0x51; 50: bs[k + 1] = 0x0B; 51: high = new BigInteger(bs); 52: } 53: } 54: } 55: }
上述程式中第 27 到 53 行的 GetLowAndHigh 方法用於獲得指定的大整數的平方根的下限和上限,然後在第 8 到 25 行的 Sqrt 方法中使用二分搜尋來找出所求的平方根。
BigInteger.ToByteArray 方法將 BigInteger 轉換為位元組陣列。對於大於零的 BigInteger ,轉換後的位元組陣列的長度固定的情況下,最小值為 00-80-00-00-00 形式,最大值為 7F-FF-FF-FF-FF 形式,剛好比下一組最小值小一。如下表所示:
n | x | Sqrt(x) |
---|---|---|
2 | 00-80 | 0B |
3 | 00-80-00 | 00-B5 |
4 | 00-80-00-00 | 0B-50 |
5 | 00-80-00-00-00 | 00-B5-04 |
6 | 00-80-00-00-00-00 | 0B-50-4F |
7 | 00-80-00-00-00-00-00 | 00-B5-04-F3 |
8 | 00-80-00-00-00-00-00-00 | 0B-50-4F-33 |
9 | 00-80-00-00-00-00-00-00-00 | 00-B5-04-F3-33 |
從上表中可以看到,假設 x 轉換為位元組陣列後,長度為 n ,則 Sqrt(x) 轉換為位元組陣列後,其長度為 n / 2 + 1。
對於 n 為偶數的情況(程式中第 40 到 43 行):
- 最小值大於 00-0B-00-00-...
- 最大值小於 00-B6-00-00-...
對於 n 為奇數的情況(程式中第 47 到 51 行):
- 最小值大於 00-B5-00-00-...
- 最大值小於 0B-51-00-00-...
在 .NET Framework 2.0 中並沒有 BigInteger。我以前自己用 C# 寫過 BigInteger,也實現了 Sqrt 方法。可以參見以下隨筆:
使用快速傅立葉變換實現 BigInteger 時,是呼叫 BigArithmetic 類的靜態方法。其中 Sqrt 方法是使用牛頓迭代法計算平方根:
Ui+1 = Ui (3 - VUi2) / 2
則 U∞二次收斂於 1/√V,最後乘以 V 就得到√V。求平方根的速度比本文中的二分搜尋法要快。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/12639172/viewspace-676663/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 學習方法淺談
- 淺談模板方法模式模式
- 淺談php count()函式方法PHP函式
- 淺談jQuery中的工具方法jQuery
- 淺談jQuery中$.proxy()工具方法jQuery
- 淺談自己的學習方法
- 寫給新手 - 淺談脫殼方法
- 淺談API函式呼叫的方法API函式
- 淺談班級高效管理方法
- 淺談 Dart 類與類的基本方法Dart
- 淺談 CC 攻擊的防護方法
- python淺談正則的常用方法Python
- 淺談繞過WAF的數種方法
- 淺淺談ReduxRedux
- 淺談 JavaScript 中 Array 型別的方法使用JavaScript型別
- 淺談Tomcat伺服器優化方法Tomcat伺服器優化
- 淺談醫學SCI論文選題方法
- 淺談機房接地線的製作方法
- 淺淺淺談JavaScript作用域JavaScript
- 淺談深拷貝與淺拷貝?深拷貝幾種方法。
- Celery淺談
- 淺談flutterFlutter
- 淺談JMM
- 淺談反射反射
- 淺談mockMock
- 淺談SYNPROXY
- 淺談Disruptor
- 淺談IHttpHandlerHTTP
- 淺談 PromisePromise
- 淺談PWA
- 淺談vuexVue
- 淺談JavaScriptJavaScript
- 淺談RMQMQ
- 淺談Zilliqa
- 淺談RxJavaRxJava
- 淺談NginxNginx
- 淺談 JavaScriptCoreJavaScript
- 淺談MVPMVP