Jak zaokrąglić do najbliższej 0,5?

103

Muszę wyświetlać oceny, a do tego potrzebuję następujących przyrostów:

Jeśli liczba wynosi 1,0, to powinno być równe 1
Jeśli liczba wynosi 1,1, powinno być równe 1
Jeśli liczba wynosi 1,2, powinno być równe 1
Jeśli liczba wynosi 1,3, powinno być równe 1,5
Jeśli liczba wynosi 1,4, powinno być równe 1,5
Jeśli liczba wynosi 1,5, to powinno być równe 1,5
Jeśli liczba wynosi 1,6, to powinno być równe 1,5
Jeśli liczba wynosi 1,7, to powinno być równe 1,5
Jeśli liczba wynosi 1,8, to powinno być równe 2,0
Jeśli liczba wynosi 1,9, to 2,0
Jeśli liczba wynosi 2,0, powinna być równa 2,0
Jeśli liczba wynosi 2,1, powinna być równa 2,0
i tak dalej ...

Czy istnieje prosty sposób obliczenia wymaganych wartości?

Murtaza Mandvi
źródło
„i tak dalej…” czy obejmuje to liczby skończone zbliżone do maksymalnej możliwej do przedstawienia wartości?
chux - Przywróć Monikę

Odpowiedzi:

207

Pomnóż swoją ocenę przez 2, zaokrąglij używając Math.Round(rating, MidpointRounding.AwayFromZero), a następnie podziel tę wartość przez 2.

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

John Rasch
źródło
4
Nie muszę pisać dla manekinów, potrzebuję pisać dla smarties
Neil N
3
Nie idealny! a co z przepełnieniem całkowitoliczbowym! Możesz obliczyć tylko połowę możliwych liczb całkowitych.
Elazar Leibovich
2
@Elazar - gdybyś mógł zająć tak wysokie miejsce, jak 1073,741,823 miejsce, nie przychodzi mi do głowy ani jeden przypadek użycia, w którym obchodziłoby Cię, czy jest to „miliard i pół” czy „miliard jeden” - jeśli to naprawdę problem to jest coś z natury wadliwego w schemacie rankingu :)
John Rasch,
4
Najpierw podziel, a następnie pomnóż. To wyeliminuje problem przepełnienia, a także pozwoli zaokrąglić do dowolnej liczby.
Benjol
8
@Benjol, najpierw podzielenie, a następnie zaokrąglenie spowoduje zaokrąglenie do najbliższego współczynnika 2, a nie połowy. Niepoprawne.
Nacht
67

Pomnóż przez 2, zaokrąglij, a następnie podziel przez 2

jeśli chcesz najbliższy kwartał, pomnóż przez 4, podziel przez 4 itd

Neil N.
źródło
16

Oto kilka metod, które napisałem, które zawsze zaokrągla w górę lub w dół do dowolnej wartości.

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
źródło
2

Istnieje kilka opcji. Jeśli zależy Ci na wydajności, przetestuj je, aby zobaczyć, która działa najszybciej w dużej pętli.

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;
}
John Fisher
źródło
To powinno działać, ale nie jest tak eleganckie, jak niektóre podane rozwiązania. Mnożenie i korzystanie z biblioteki systemowej jest po prostu sexy.
captncraig,
Wydajność jest zwykle ważniejsza, a to może zająć mniej czasu niż rozwiązania mnożenia i dzielenia.
John Fisher,
3
Ten kod jest nieprawidłowy. Ponieważ arytmetyka z podwójnymi liczbami zwykle ma małe błędy zaokrągleń, operacja taka jak 4,8 - 4,0 może dać na przykład 0,799999 .... W tym przypadku powyższy kod zaokrągliłby do 4,5. Lepiej byłoby również użyć Math.Floor zamiast Math.Truncate, ponieważ w tej chwili liczby ujemne nie są poprawnie zaokrąglane. Wolę zaakceptowaną odpowiedź, ponieważ jest prostsza i mniej podatna na błędy wdrożeniowe.
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);
Akash Kava
źródło
1

Wygląda na to, że musisz zaokrąglić do najbliższej 0,5. Nie widzę wersji roundw C # API, która to robi (jedna wersja wymaga zaokrągleń do liczby cyfr dziesiętnych, co nie jest tym samym).

Zakładając, że masz do czynienia tylko z całkowitymi liczbami dziesiątych, wystarczy to obliczyć round (num * 2) / 2. Jeśli używasz dowolnie dokładnych liczb dziesiętnych, sprawa jest trudniejsza. Miejmy nadzieję, że nie.

Paul Brinkley
źródło
0

Z tym problemem też miałem trudności. Koduję głównie w Actionscript 3.0, który jest podstawowym kodowaniem dla platformy Adobe Flash, ale są podobieństwa w językach:

Rozwiązanie, które wymyśliłem, jest następujące:

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

To wszystko. Zwróć uwagę na użycie „liczb” i „liczb całkowitych” oraz sposób ich przetwarzania.

Powodzenia!

Jason Henn
źródło
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
źródło
4
Ten kod nie wygląda jak C #, jak chciał w pytaniu. Co to robi? Podaj wyjaśnienie, a nie tylko fragment kodu w nieokreślonym języku.
AdrianHHH
-1

Prawidłowy sposób to:

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

                return finalPrice;

            }
Carca
źródło