Как округлить до 0,5?


103

Мне нужно отображать рейтинги, и для этого мне нужны следующие приращения:

Если число 1,0, оно должно быть равно 1
Если число 1,1 должно быть равно 1
Если число 1,2 должно быть равно 1
Если число 1,3 должно быть равно 1,5
Если число 1,4 должно быть равно 1.5
Если число 1,5 должно быть равно 1,5
Если число 1,6 должно быть равно 1,5
Если число 1,7 должно быть равно 1,5
Если число 1,8 должно быть равно 2,0
Если число 1,9 должно быть равно 2.0
Если число 2.0 должно быть равно 2.0
Если число 2.1 должно быть равно 2.0
и так далее ...

Есть ли простой способ вычислить требуемые значения?


"и так далее ..." включает ли это конечные числа, близкие к максимально представимому значению?
chux

Ответы:


208

Умножьте свой рейтинг на 2, затем округлите с помощью Math.Round(rating, MidpointRounding.AwayFromZero), затем разделите полученное значение на 2.

Math.Round(value * 2, MidpointRounding.AwayFromZero) / 2


4
Мне не нужно печатать для чайников, мне нужно печатать для умных
Нил Н.

3
Не идеально! как насчет целочисленного переполнения! Вы можете вычислить только половину возможных целых чисел.
Элазар Лейбович

2
@Elazar - если бы вас можно было поставить на 1 073 741 823-е место, я не могу придумать ни одного варианта использования, где бы вас волновало, будет ли это «полтора миллиарда» или «один миллиард один» - если это действительно проблема тогда в схеме ранжирования есть что-то изначально несовершенное :)
Джон Раш

4
Сначала разделите, затем умножьте. Это устранит проблему переполнения, а также позволит округлить до произвольного числа.
Benjol

8
@Benjol, сначала деление, а затем округление приведет к округлению до ближайшего множителя 2, а не до половины. Не верно.
Ночь,

66

Умножить на 2, округлить, затем разделить на 2

если вам нужен ближайший квартал, умножьте на 4, разделите на 4 и т. д.


16

Вот несколько написанных мной методов, которые всегда будут округлять любое значение в большую или меньшую сторону.

public static Double RoundUpToNearest(Double passednumber, Double roundto)
{
    // 105.5 up to nearest 1 = 106
    // 105.5 up to nearest 10 = 110
    // 105.5 up to nearest 7 = 112
    // 105.5 up to nearest 100 = 200
    // 105.5 up to nearest 0.2 = 105.6
    // 105.5 up to nearest 0.3 = 105.6

    //if no rounto then just pass original number back
    if (roundto == 0)
    {
        return passednumber;
    }
    else
    {
        return Math.Ceiling(passednumber / roundto) * roundto;
    }
}

public static Double RoundDownToNearest(Double passednumber, Double roundto)
{
    // 105.5 down to nearest 1 = 105
    // 105.5 down to nearest 10 = 100
    // 105.5 down to nearest 7 = 105
    // 105.5 down to nearest 100 = 100
    // 105.5 down to nearest 0.2 = 105.4
    // 105.5 down to nearest 0.3 = 105.3

    //if no rounto then just pass original number back
    if (roundto == 0)
    {
        return passednumber;
    }
    else
    {
        return Math.Floor(passednumber / roundto) * roundto;
    }
}

2

Есть несколько вариантов. Если производительность вызывает беспокойство, проверьте их, чтобы увидеть, какой из них работает быстрее всего в большом цикле.

double Adjust(double input)
{
    double whole = Math.Truncate(input);
    double remainder = input - whole;
    if (remainder < 0.3)
    {
        remainder = 0;
    }
    else if (remainder < 0.8)
    {
        remainder = 0.5;
    }
    else
    {
        remainder = 1;
    }
    return whole + remainder;
}

Это должно сработать, но это не так элегантно, как некоторые приведенные решения. Умножать и использовать системную библиотеку просто сексуально.
captncraig

Производительность обычно более важна, и это может занять меньше времени, чем решения умножения и деления.
Джон Фишер,

3
Этот код неверен. Поскольку арифметика с числами типа double обычно имеет небольшие ошибки округления, такая операция, как 4,8 - 4,0, может дать, например, 0,799999 .... В этом случае приведенный выше код будет округлен до 4,5. Также лучше было бы использовать Math.Floor вместо Math.Truncate, потому что сейчас отрицательные числа не округляются правильно. Я предпочитаю принятый ответ, потому что он проще и менее подвержен ошибкам реализации.
Accipitridae

1
decimal d = // your number..

decimal t = d - Math.Floor(d);
if(t >= 0.3d && t <= 0.7d)
{
    return Math.Floor(d) + 0.5d;
}
else if(t>0.7d)
    return Math.Ceil(d);
return Math.Floor(d);

1

Похоже, вам нужно округлить до 0,5. Я не вижу roundв C # API версии, которая бы это делала (одна версия требует округления до ряда десятичных цифр, что не одно и то же).

Предполагая, что вам нужно иметь дело только с целыми числами, равными десятым, этого достаточно для вычисления round (num * 2) / 2. Если вы используете произвольно точные десятичные дроби, это становится сложнее. Будем надеяться, что нет.


0

У меня тоже были трудности с этой проблемой. Я кодирую в основном ActionScript 3.0, который является базовым кодом для платформы Adobe Flash, но есть сходства на языках:

Решение, которое я придумал, следующее:

//Code for Rounding to the nearest 0.05
var r:Number = Math.random() * 10;  // NUMBER - Input Your Number here
var n:int = r * 10;   // INTEGER - Shift Decimal 2 places to right
var f:int = Math.round(r * 10 - n) * 5;// INTEGER - Test 1 or 0 then convert to 5
var d:Number = (n + (f / 10)) / 10; //  NUMBER - Re-assemble the number

trace("ORG No: " + r);
trace("NEW No: " + d);

Вот и все. Обратите внимание на использование «чисел» и «целых чисел» и способ их обработки.

Удачи!


0
Public Function Round(ByVal text As TextBox) As Integer
    Dim r As String = Nothing
    If text.TextLength > 3 Then
        Dim Last3 As String = (text.Text.Substring(text.Text.Length - 3))
        If Last3.Substring(0, 1) = "." Then
            Dim dimcalvalue As String = Last3.Substring(Last3.Length - 2)
            If Val(dimcalvalue) >= 50 Then
                text.Text = Val(text.Text) - Val(Last3)
                text.Text = Val(text.Text) + 1
            ElseIf Val(dimcalvalue) < 50 Then
                text.Text = Val(text.Text) - Val(Last3)
            End If
        End If
    End If
    Return r
End Function

5
Этот код не похож на C #, как того требует вопрос. Что оно делает? Пожалуйста, дайте объяснение, а не просто кусок кода на неопределенном языке.
AdrianHHH

-1

Правильный способ сделать это:

  public static Decimal GetPrice(Decimal price)
            {
                var DecPrice = price / 50;
                var roundedPrice = Math.Round(DecPrice, MidpointRounding.AwayFromZero);
                var finalPrice = roundedPrice * 50;

                return finalPrice;

            }
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.