2012-08-08 107 views
7

我想計算一條直線的斜率。劃分BigIntegers以返回雙精度值

public sealed class Point 
{ 
    public System.Numerics.BigInteger x = 0; 
    public System.Numerics.BigInteger y = 0; 

    public double CalculateSlope (Point point) 
    { 
     return ((point.Y - this.Y)/(point.X - this.X)); 
    } 
} 

我知道的BigInteger返回除法結果加上其餘但我不知道如何使用它獲得雙重一個DivRem功能。我正在處理的數字是遠遠超出Int64.MaxValue的範圍,所以其餘的本身可能超出範圍來計算傳統的劃分。

編輯: 不知道它是否有幫助,但我只處理正整數(> = 1)。

重要事項:我只需要幾個小數點的精度(5應該足夠我的目的)。

+0

您需要它有多精確? – 2012-08-08 20:14:48

+0

你正在處理的數字是什麼。請顯示數字的性質。 – MethodMan 2012-08-08 20:16:13

+0

@AustinSalonen:精度越高越好,但即使精確到幾位十進制數字也足以達到我想要的位置。 – 2012-08-08 20:20:11

回答

5

BigRational庫的轉換運算符翻倍。此外,請記住將無窮大作爲垂直線的特例返回,您將得到一個除以零的異常與您當前的代碼。可能最好先計算X1 - X2,如果它爲零則返回無窮大,然後進行除法,以避免冗餘操作。

+0

有趣。 .NET 4中不存在這個類嗎?如果它是測試版或候選版本,那麼不幸的是我不能在生產代碼中使用它。 – 2012-08-08 20:50:10

+0

這是一個測試版。你爲什麼不能使用它? – Random832 2012-08-08 22:28:07

+0

這是一個生產應用程序。質量保證不允許測試版庫。 – 2012-08-09 01:05:03

1

這不處理負面,但希望給你一個開始。

 double doubleMax = double.MaxValue; 
     BigInteger numerator = 120; 
     BigInteger denominator = 50;   
     if (denominator != 0) 
     { 
      Debug.WriteLine(numerator/denominator); 
      Debug.WriteLine(numerator % denominator); 
      BigInteger ansI = numerator/denominator; 
      if (ansI < (int)doubleMax) 
      { 
       double slope = (double)ansI + ((double)(numerator % denominator)/(double)denominator); ; 
       Debug.WriteLine(slope); 
      } 
     } 
+0

謝謝。但是,如果整體結果在Int32或UInt64內,這隻會起作用。考慮將N除以3,其中N具有10,000,000個數字。 – 2012-08-08 20:35:29

+0

@RaheelKhan沒錯。閱讀問題public double CalculateSlope。如果它大於兩倍,答案不能被翻倍。 – Paparazzi 2012-08-08 20:41:19

+0

當然。斜率本身總是在-1.0和1.0之間。這是正在失去一個很大的精度。 – 2012-08-08 20:43:21

4

從Codeplex獲得BigRational。它是微軟的Base Class Library的一部分,因此它是.Net的一項工作。一旦你的,然後做一些事情,如:

System.Numerics.BigInteger x = GetDividend() ; 
System.Numerics.BigInteger y = GetDivisor() ; 

BigRational r  = new BigRational(x , y) ; 
double  value = (double) r ; 

與必然溢/下溢/的精度,當然,另一個問題損失的處理。

既然你不能在BigRational庫拖放到你的代碼,顯然,其他的辦法是走出right algorithms book並推出自己的...

最簡單的方法,當然,滾動」自己的「,因爲有理數表示爲兩個整數的比率(除法),是從BigRational類抓取顯式轉換爲雙運算符並調整它以適應。我花了大約15分鐘。

關於我所做的唯一重大修改是當結果爲正數或負數零/無窮時,結果的符號如何設置。當我在它時,我將它轉換爲BigInteger擴展方法爲您:

public static class BigIntExtensions 
{ 

    public static double DivideAndReturnDouble(this BigInteger x , BigInteger y) 
    { 
    // The Double value type represents a double-precision 64-bit number with 
    // values ranging from -1.79769313486232e308 to +1.79769313486232e308 
    // values that do not fit into this range are returned as +/-Infinity 
    if (SafeCastToDouble(x) && SafeCastToDouble(y)) 
    { 
     return (Double) x/(Double) y; 
    } 

    // kick it old-school and figure out the sign of the result 
    bool isNegativeResult = ((x.Sign < 0 && y.Sign > 0) || (x.Sign > 0 && y.Sign < 0)) ; 

    // scale the numerator to preseve the fraction part through the integer division 
    BigInteger denormalized = (x * s_bnDoublePrecision)/y ; 
    if (denormalized.IsZero) 
    { 
     return isNegativeResult ? BitConverter.Int64BitsToDouble(unchecked((long)0x8000000000000000)) : 0d; // underflow to -+0 
    } 

    Double result = 0    ; 
    bool isDouble = false   ; 
    int scale = DoubleMaxScale ; 

    while (scale > 0) 
    { 
     if (!isDouble) 
     { 
     if (SafeCastToDouble(denormalized)) 
     { 
      result = (Double) denormalized; 
      isDouble = true; 
     } 
     else 
     { 
      denormalized = denormalized/10 ; 
     } 
     } 
     result = result/10 ; 
     scale-- ; 
    } 

    if (!isDouble) 
    { 
     return isNegativeResult ? Double.NegativeInfinity : Double.PositiveInfinity; 
    } 
    else 
    { 
     return result; 
    } 

    } 

    private const   int  DoubleMaxScale  = 308 ; 
    private static readonly BigInteger s_bnDoublePrecision = BigInteger.Pow(10 , DoubleMaxScale) ; 
    private static readonly BigInteger s_bnDoubleMaxValue = (BigInteger) Double.MaxValue; 
    private static readonly BigInteger s_bnDoubleMinValue = (BigInteger) Double.MinValue; 

    private static bool SafeCastToDouble(BigInteger value) 
    { 
    return s_bnDoubleMinValue <= value && value <= s_bnDoubleMaxValue; 
    } 

} 
+0

謝謝。不幸的是,我不能在生產代碼中使用BigRational,因爲它處於測試階段。論壇和書籍應該是答案。 – 2012-08-08 21:05:32

+1

@RaheelKhan:或者您可以從BigRational庫中去除顯式轉換運算符並根據需要進行修改。我花了大約15分鐘(見我編輯的答案)。 – 2012-08-08 23:34:52

+0

謝謝。考慮到替代方案,這可能是唯一的出路。在標記正確的答案之前,我會花一些時間來消化這個並進行測試。 – 2012-08-09 01:10:29