Come faccio ad arrotondare allo 0,5 più vicino?


103

Devo visualizzare le valutazioni e per questo ho bisogno di incrementi come segue:

Se il numero è 1.0 dovrebbe essere uguale a 1
Se il numero è 1.1 dovrebbe essere uguale a 1
Se il numero è 1.2 dovrebbe essere uguale a 1
Se il numero è 1.3 dovrebbe essere uguale a 1.5
Se il numero è 1.4 dovrebbe essere uguale a 1.5
Se il numero è 1.5 dovrebbe essere uguale a 1.5
Se il numero è 1.6 dovrebbe essere uguale a 1.5
Se il numero è 1.7 dovrebbe essere uguale a 1.5
Se il numero è 1.8 dovrebbe essere uguale a 2.0
Se il numero è 1.9 dovrebbe essere uguale a 2.0
Se il numero è 2.0 dovrebbe essere uguale a 2.0
Se il numero è 2.1 dovrebbe essere uguale a 2.0
e così via ...

C'è un modo semplice per calcolare i valori richiesti?


"e così via ..." include numeri finiti vicini al valore massimo rappresentabile?
chux - Ripristina Monica il

Risposte:


207

Moltiplica il tuo punteggio per 2, quindi arrotonda usando Math.Round(rating, MidpointRounding.AwayFromZero), quindi dividi quel valore per 2.

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


4
Non ho bisogno di digitare per i manichini, ho bisogno di digitare per gli smarties
Neil N

3
Non perfetto! che dire dell'intero overflow! È possibile calcolare solo la metà dei possibili numeri interi.
Elazar Leibovich

2
@Elazar - se potessi essere classificato fino a 1.073.741.823, non riesco a pensare a un caso d'uso singolo in cui ti importerebbe se fosse "un miliardo e mezzo" o "un miliardo di uno" - se questo è davvero un problema poi c'è qualcosa di intrinsecamente difettoso nello schema di classifica :)
John Rasch il

4
Dividi prima, poi moltiplica. Ciò eliminerà il problema di overflow e consentirà anche di arrotondare a un numero arbitrario.
Benjol

8
@Benjol, dividendo prima e poi arrotondando, verrà arrotondato al fattore 2 più vicino, invece che alla metà. Non corretto.
Nacht

67

Moltiplicare per 2, arrotondare, quindi dividere per 2

se vuoi un quarto più vicino, moltiplica per 4, dividi per 4, ecc


16

Ecco un paio di metodi che ho scritto che arrotondano sempre per eccesso o per difetto a qualsiasi valore.

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

Ci sono diverse opzioni. Se le prestazioni sono un problema, provale per vedere quale funziona più velocemente in un ciclo di grandi dimensioni.

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

Questo dovrebbe funzionare, ma non è così elegante come alcune soluzioni fornite. Moltiplicare e utilizzare la libreria di sistema è semplicemente sexy.
captncraig

Le prestazioni sono generalmente più importanti e ciò potrebbe richiedere meno tempo rispetto alle soluzioni di moltiplicazione e divisione.
John Fisher,

3
Questo codice non è corretto. Poiché l'aritmetica con i doppi di solito ha alcuni piccoli errori di arrotondamento, un'operazione come 4.8 - 4.0 potrebbe dare ad esempio 0.799999 .... In questo caso il codice sopra sarebbe arrotondato a 4.5. Inoltre sarebbe meglio usare Math.Floor invece di Math.Truncate, perché in questo momento i numeri negativi non vengono arrotondati correttamente. Preferisco la risposta accettata, perché è più semplice e meno soggetta a errori di implementazione.
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

Sembra che tu debba arrotondare allo 0,5 più vicino. Non vedo alcuna versione diround dell'API C # che esegue questa operazione (una versione richiede un numero di cifre decimali per arrotondare, il che non è la stessa cosa).

Supponendo che tu abbia a che fare solo con numeri interi di decimi, è sufficiente calcolare round (num * 2) / 2. Se stai usando decimali arbitrariamente precisi, diventa più complicato. Speriamo che tu non lo faccia.


0

Ho avuto difficoltà anche con questo problema. Codice principalmente in Actionscript 3.0 che è la codifica di base per la piattaforma Adobe Flash, ma ci sono somiglianze nelle lingue:

La soluzione che ho trovato è la seguente:

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

Questo è praticamente tutto. Nota l'uso di "Numbers" e "Integers" e il modo in cui vengono elaborati.

In bocca al lupo!


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

4
Questo codice non ha l'aspetto di C # come desiderato nella domanda. Che cosa fa? Fornisci una spiegazione piuttosto che un blocco di codice in una lingua non specificata.
AdrianHHH

-1

Il modo corretto per farlo è:

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

                return finalPrice;

            }
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.