8

直線の傾きを計算したい。

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関数があることは知っていますが、それを適用してdoubleを取得する方法がわかりません。私が扱っている数値はInt64.MaxValueの範囲をはるかに超えているため、余り自体は従来の除算で計算するには範囲外である可能性があります。

編集:それが役立つかどうかはわかりませんが、私は正の整数(> = 1)のみを扱っています。

重要:必要な小数点以下の桁数はわずかです(私の目的には5で十分です)。

4

3 に答える 3

6

CodeplexからBigRationalを入手してください。これはMicrosoftの基本クラスライブラリの一部であるため、.Netで進行中です。それができたら、次のようなことを行います。

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

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

もちろん、避けられないオーバーフロー/アンダーフロー/精度の低下に対処することは別の問題です。

BigRationalライブラリをコードにドロップすることはできないので、明らかに、他のアプローチは、適切なアルゴリズムの本を取り出して、独自のアルゴリズムを作成することです...

もちろん、ここで「自分で転がす」簡単な方法は、有理数が2つの整数の比率(除算)として表されるため、BigRationalクラスからdouble演算子への明示的な変換を取得し、それに合わせて微調整することです。約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;
  }

}
于 2012-08-08T21:00:18.047 に答える
5

BigRationalライブラリには、doubleへの変換演算子があります。

また、垂直線の特殊なケースとして無限大を返すことを忘れないでください。現在のコードではゼロ除算の例外が発生します。おそらく、最初にX1-X2を計算し、ゼロの場合は無限大を返し、次に除算を実行して、冗長な操作を回避するのが最善です。

于 2012-08-08T20:38:09.323 に答える
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);
            }
        }
于 2012-08-08T20:28:40.913 に答える