在十进制数字的n位置找到数字的最佳方法是什么?

Eli*_*jah 15 c# algorithm rounding

背景

我正在进行一个对称的舍入课程,我发现我对如何最好地找到x位置的数字感到困惑,我将会四舍五入.我确信有一种有效的数学方法可以找到单个数字并返回它而不必求助于字符串解析.

问题

假设,我有以下(C#)伪代码:

var position = 3;
var value = 102.43587m;
// I want this no ? (that is 5)

protected static int FindNDigit(decimal value, int position)
{
    // This snippet is what I am searching for
}
Run Code Online (Sandbox Code Playgroud)

另外,值得注意的是,如果我的值是整数,我将需要为FindNDigit的结果返回零.

有没有人对我应该如何处理这个问题有任何暗示?这是一件非常明显的事情吗?

And*_*rey 28

(int)(value * Math.Pow(10, position)) % 10
Run Code Online (Sandbox Code Playgroud)

  • 您应该首先剥离"位置"左侧的数字,以避免不必要的溢出. (2认同)

Jus*_*ier 25

怎么样:

(int)(double(value) * Math.Pow(10, position)) % 10
Run Code Online (Sandbox Code Playgroud)

基本上你乘以10 ^ pos以便将该数字移动到一个位置,然后使用模数运算符%来除去数字的其余部分.

  • +1包括解释:).我确信代码会将此作为评论. (6认同)

xof*_*ofz 5

using System;

public static class DecimalExtensions
{
    public static int DigitAtPosition(this decimal number, int position)
    {
        if (position <= 0)
        {
            throw new ArgumentException("Position must be positive.");
        }

        if (number < 0)
        {
            number = Math.Abs(number);
        }

        number -= Math.Floor(number);

        if (number == 0)
        {
            return 0;
        }

        if (position == 1)
        {
            return (int)(number * 10);
        }

        return (number * 10).DigitAtPosition(position - 1);
    }
}
Run Code Online (Sandbox Code Playgroud)

编辑:如果您愿意,您可以将递归调用与初始调用分开,以在递归期间删除初始条件检查:

using System;

public static class DecimalExtensions
{
    public static int DigitAtPosition(this decimal number, int position)
    {
        if (position <= 0)
        {
            throw new ArgumentException("Position must be positive.");
        }

        if (number < 0)
        {
            number = Math.Abs(number);
        }

        return number.digitAtPosition(position);
    }

    static int digitAtPosition(this decimal sanitizedNumber, int validPosition)
    {
        sanitizedNumber -= Math.Floor(sanitizedNumber);

        if (sanitizedNumber == 0)
        {
            return 0;
        }

        if (validPosition == 1)
        {
            return (int)(sanitizedNumber * 10);
        }

        return (sanitizedNumber * 10).digitAtPosition(validPosition - 1);
    }
Run Code Online (Sandbox Code Playgroud)

这是一些测试:

using System;
using Xunit;

public class DecimalExtensionsTests
{
                         // digit positions
                         // 1234567890123456789012345678
    const decimal number = .3216879846541681986310378765m;

    [Fact]
    public void Throws_ArgumentException_if_position_is_zero()
    {
        Assert.Throws<ArgumentException>(() => number.DigitAtPosition(0));
    }

    [Fact]
    public void Throws_ArgumentException_if_position_is_negative()
    {
        Assert.Throws<ArgumentException>(() => number.DigitAtPosition(-5));
    }

    [Fact]
    public void Works_for_1st_digit()
    {
        Assert.Equal(3, number.DigitAtPosition(1));
    }

    [Fact]
    public void Works_for_28th_digit()
    {
        Assert.Equal(5, number.DigitAtPosition(28));
    }

    [Fact]
    public void Works_for_negative_decimals()
    {
        const decimal negativeNumber = -number;
        Assert.Equal(5, negativeNumber.DigitAtPosition(28));
    }

    [Fact]
    public void Returns_zero_for_whole_numbers()
    {
        const decimal wholeNumber = decimal.MaxValue;
        Assert.Equal(0, wholeNumber.DigitAtPosition(1));
    }

    [Fact]
    public void Returns_zero_if_position_is_greater_than_the_number_of_decimal_digits()
    {
        Assert.Equal(0, number.DigitAtPosition(29));
    }

    [Fact]
    public void Does_not_throw_if_number_is_max_decimal_value()
    {
        Assert.DoesNotThrow(() => decimal.MaxValue.DigitAtPosition(1));
    }

    [Fact]
    public void Does_not_throw_if_number_is_min_decimal_value()
    {
        Assert.DoesNotThrow(() => decimal.MinValue.DigitAtPosition(1));
    }

    [Fact]
    public void Does_not_throw_if_position_is_max_integer_value()
    {
        Assert.DoesNotThrow(() => number.DigitAtPosition(int.MaxValue));
    }
}
Run Code Online (Sandbox Code Playgroud)