查找小数中第 n 位的数字的最佳方法是什么?

发布于 2024-09-03 13:22:50 字数 449 浏览 5 评论 0原文

背景

我正在研究一个对称舍入类,我发现我陷入了如何最好地找到我将要舍入的位置 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
}

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

有人对我应该如何解决这个问题有任何提示吗?这是我错过的明显的东西吗?

Background

I'm working on a symmetric rounding class and I find that I'm stuck with regards to how to best find the number at position x that I will be rounding. I'm sure there is an efficient mathematical way to find the single digit and return it without having to resort to string parsing.

Problem

Suppose, I have the following (C#) psuedo-code:

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
}

Also, it is worth noting that if my value is a whole number, I will need to return a zero for the result of FindNDigit.

Does anyone have any hints on how I should approach this problem? Is this something that is blaringly obvious that I'm missing?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

痴骨ら 2024-09-10 13:22:51

以前的解决方案都不适合我,所以这里是一个有效的解决方案:

var result = value / Math.Pow(10, Math.Truncate((Math.Log10(value) + 1) -position));
返回(int)(结果%10);

None of the previous solutions worked for me, so here is a working one :

var result = value / Math.Pow(10, Math.Truncate((Math.Log10(value) + 1) - position));
return (int)(result % 10);

瘫痪情歌 2024-09-10 13:22:50
(int)(value * Math.Pow(10, position)) % 10
(int)(value * Math.Pow(10, position)) % 10
守不住的情 2024-09-10 13:22:50

怎么样:

(int)(double(value) * Math.Pow(10, position)) % 10

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

How about:

(int)(double(value) * Math.Pow(10, position)) % 10

Basically you multiply by 10 ^ pos in order to move that digit to the one's place, and then you use the modulus operator % to divide out the rest of the number.

乄_柒ぐ汐 2024-09-10 13:22:50
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);
    }
}

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

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);
    }

以下是一些测试:

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));
    }
}
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);
    }
}

Edit:
If you wish, you may separate the recursive call from the initial call, to remove the initial conditional checks during recursion:

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);
    }

Here's a few tests:

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));
    }
}
灼疼热情 2024-09-10 13:22:50

编辑:这里完全有错误和相反的答案。我正在计算小数点左侧而不是右侧的位置。请参阅正确的代码的赞成答案。

Edited: Totally had the wrong and opposite answer here. I was calculating the position to the left of the decimal instead of the right. See the upvoted answers for the correct code.

思念满溢 2024-09-10 13:22:50

我找到了这个

public int ValueAtPosition(int value, int position)
{
    var result = value / (int)Math.Pow(10, position);
    result = result % 10;
    return result;
}

还有这个知道完整值(即:111,位置3 = 100,抱歉我不知道正确的名称):

public int FullValueAtPosition(int value, int position)
{
    return this.ValueAtPosition(value, position) * (int)Math.Pow(10, position);
}

I found this one here working:

public int ValueAtPosition(int value, int position)
{
    var result = value / (int)Math.Pow(10, position);
    result = result % 10;
    return result;
}

And also this one to know the full value (i.e.: 111, position 3 = 100 , sorry I don't know the proper name):

public int FullValueAtPosition(int value, int position)
{
    return this.ValueAtPosition(value, position) * (int)Math.Pow(10, position);
}
無心 2024-09-10 13:22:50

这个怎么样:

protected static int FindNDigit(decimal value, int position)
{
    var index = value.ToString().IndexOf(".");
    position = position + index;
    return (int)Char.GetNumericValue(value.ToString(), position);
}

How about this:

protected static int FindNDigit(decimal value, int position)
{
    var index = value.ToString().IndexOf(".");
    position = position + index;
    return (int)Char.GetNumericValue(value.ToString(), position);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文