首页 > 解决方案 > 如何在C#中手动计算数字的第n个根

问题描述

我正在尝试编写一个算法,该算法将计算在 C# 中作为字符串(实际上)提供给算法的数字的第 N 个根。我现在所拥有的计算平方根,但不计算其他根,我想修改特定于平方根的算法部分,以便将其推广到第 N 个根。

我一直在使用两篇关于手动计算平方根和 N 次根的 WikiHow 文章(代码注释中的 URL),并且我相信我所拥有的唯一特定于平方根方法的部分是在我的本地函数中隔离的,(long, long) GetDigit( long segment ). 我不理解与平方根方法不同的 N 次根方法中的数学,我这样做是为了编程练习并开发我自己的数字库,然后通常会有用,而不是作为数学练习。我希望有人会看到这个已经知道 C# 和所涉及的数学的问题。

我说数字“实际上”作为字符串提供给算法,因为我正在开发自己的“数字”类型,它将分子和分母都存储为 BigIntegers,因此它具有 BigIntegers 的无限大小优势并且还支持小数点。

出于这个问题的目的,该算法也可能将数字作为字符串接收,因此我对其进行了一些修改,以便在 Number-type 参数(在代码中更改为对象参数)时,它将接受并使用字符串下面)为空。这样,您应该能够轻松地测试您所做的任何修改,而不必担心我的 Number 类型的细节。

public static string NthRoot( int nth, object aNumber, string aStringInteger = "" )
{
    Debug.WriteLine( $"\nFINDING THE {nth}TH ROOT OF {aNumber}." );
    string[] Segments = GetSegments( aNumber?.Integer.ToString( ) ?? aStringInteger );
    Debug.WriteLine( $"Segment Count: {Segments.Length}." );

    string Result = "";
    long SegmentIndex = 0;
    long NextSegment = Convert.ToInt64( Segments[SegmentIndex] );
    long CurrentDigit = 0;
    long SubtractAmount;
    (CurrentDigit, SubtractAmount) = GetDigit( NextSegment );
    Result += CurrentDigit.ToString( );
    Debug.WriteLine( $"{Result}." );

    bool DoForLoop( )
    {
        for( ; SegmentIndex < Segments.Length; SegmentIndex++ )
        {
            NextSegment = (NextSegment - SubtractAmount) * (int)Math.Pow( 10, nth );
            NextSegment += Convert.ToInt64( Segments[SegmentIndex] );
            (CurrentDigit, SubtractAmount) = GetDigit( NextSegment );
            Debug.WriteLine( $"Adding {CurrentDigit} to result string." );
            Result += CurrentDigit.ToString( );
            Debug.WriteLine( $"{Result}." );
            if( Math.Pow( Result, nth ) == aNumber ) return true;
        }
        return false;
    }

    SegmentIndex++;
    if( DoForLoop( ) ) return Result;

    Result += ".";
    Segments = GetSegments( aNumber?.Decimal( ).Replace( "~", "" ) ?? "", false, 20 ); 
    //My Number type appends a ~ to repeating decimals after two repetitions of the repeating pattern.
    SegmentIndex = 0;
    DoForLoop( );
    return Result;

    string[] GetSegments( string remaining, bool padOnLeft = true, int extraPaddingOnRight = 0 )
    {
        int SegmentCount = remaining.Length / nth; //This is the number of complete nth-long sequences.
        if( remaining.Length % nth != 0 ) SegmentCount++;

        int PadLeft;
        if( padOnLeft )
        {
            PadLeft = (SegmentCount * nth) - remaining.Length;
            Debug.WriteLine( $"Padding the left with {PadLeft} zeros." );
        }
        else
        {
            PadLeft = 0;
            remaining = remaining.PadRight( SegmentCount * nth + extraPaddingOnRight, '0' );
            SegmentCount = remaining.Length / nth;
        }
        string[] _Segments = new string[SegmentCount];
        for( long s = 0; s < SegmentCount; s++ )
        {
            _Segments[s] = remaining.Substring( 0, nth - PadLeft );
            remaining = remaining.Substring( nth - PadLeft );
            PadLeft = 0;
        }
        return _Segments;
    }

    (long, long) GetDigit( long segment )
    {
        if( segment == 0 ) return (0, 0);

        long Candidate = 0;
        long Subtract = 0;
        long NextCandidate = Candidate + 1;
        if( nth != 2 ) throw new NotImplementedException( 
            "The lines that follows this exception are where I do not know how to generalize the square root " + 
            "approach to an Nth root approach." );
        //What I have is based on: method 2 at https://m.wikihow.com/Calculate-a-Square-Root-by-Hand
        //This appears to be the only part that differs from: https://www.wikihow.com/Find-Nth-Roots-by-Hand
        //The math at issue is in step 4 for Nth roots and steps 4 to 6 for square roots.
        string LeftNext = (CurrentResult( ) * 2).ToString( ) + NextCandidate.ToString( );
        long SubtractNext = Convert.ToInt64( LeftNext ) * NextCandidate;
        Debug.WriteLine( $"GetDigit( {segment} ):" );
        while( SubtractNext <= segment )
        {
            Candidate = NextCandidate;
            Subtract = SubtractNext;
            NextCandidate++;
            LeftNext = (CurrentResult( ) * 2).ToString( ) + NextCandidate.ToString( );
            SubtractNext = Convert.ToInt64( LeftNext ) * NextCandidate;
        }
        return (Candidate, Subtract);
    }

    long CurrentResult( ) => Result == "" ? 0 : Convert.ToInt64( Result.Replace( ".", "" ) );
}

标签: c#math

解决方案


推荐阅读