Как округлить до 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;
    }
}
NER1808
источник
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
user2260011
источник
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;

            }
Карка
источник