Я работаю над симметричным классом округления, и я нахожу, что застреваю относительно того, как лучше всего найти число в положении x, которое я буду округлять. Я уверен, что существует эффективный математический способ найти единственную цифру и возвратить ее, не имея необходимость обращаться для строкового представления парсинга.
Предположим, у меня есть следующий (C#) psuedo-код:
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.
У кого-либо есть какие-либо подсказки, как я должен приблизиться к этой проблеме? Это - что-то, что является blaringly очевидный, что я отсутствую?
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));
}
}
Отредактировано: Здесь был совершенно неправильный и противоположный ответ. Я вычислял позицию слева от десятичной дроби, а не справа. Правильный код см. в проголосовавших ответах.
Как насчет этого:
protected static int FindNDigit(decimal value, int position)
{
var index = value.ToString().IndexOf(".");
position = position + index;
return (int)Char.GetNumericValue(value.ToString(), position);
}
Как насчет:
(int)(double(value) * Math.Pow(10, position)) % 10
Обычно вы умножаете на 10 ^ pos
, чтобы переместить эту цифру на место, а затем используете оператор модуля %
, чтобы разделить оставшуюся часть числа.