Comment arrondir au 0,5 près?

103

Je dois afficher les évaluations et pour cela j'ai besoin des incréments comme suit:

Si le nombre est 1,0, il doit être égal à 1
Si le nombre est 1,1 doit être égal à 1
Si le nombre est 1,2 doit être égal à 1
Si le nombre est 1,3 doit être égal à 1,5
Si le nombre est 1,4 doit être égal à 1,5
Si le nombre est 1,5 doit être égal à 1,5
Si le nombre est 1,6 doit être égal à 1,5
Si le nombre est 1,7 doit être égal à 1,5
Si le nombre est 1,8 doit être égal à 2,0
Si le nombre est 1,9 doit être égal à 2.0
Si le nombre est 2.0 doit être égal à 2.0
Si le nombre est 2.1 doit être égal à 2.0
et ainsi de suite ...

Existe-t-il un moyen simple de calculer les valeurs requises?

Murtaza Mandvi
la source
"et ainsi de suite ..." cela inclut-il des nombres finis proches de la valeur maximale représentable?
chux

Réponses:

207

Multipliez votre note par 2, puis arrondissez avec Math.Round(rating, MidpointRounding.AwayFromZero), puis divisez cette valeur par 2.

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

John Rasch
la source
4
Je n'ai pas besoin de taper pour les nuls, j'ai besoin de taper pour les smarties
Neil N
3
Pas parfait! qu'en est-il du débordement d'entier! Vous ne pouvez calculer que la moitié des entiers possibles.
Elazar Leibovich
2
@Elazar - si vous pouviez être classé aussi haut que 1 073 741 823e, je ne peux pas penser à un seul cas d'utilisation où vous vous soucieriez de savoir si c'est "un milliard un et demi" ou "un milliard un" - si c'est vraiment un problème puis il y a quelque chose de fondamentalement défectueux dans le système de classement :)
John Rasch
4
Divisez d'abord, puis multipliez. Cela éliminera le problème de débordement et vous permettra également d'arrondir à un nombre arbitraire.
Benjol
8
@Benjol, en divisant d'abord, puis en arrondissant, il sera arrondi au facteur 2 le plus proche, plutôt qu'au facteur de moitié. Pas correcte.
Nacht
67

Multiplier par 2, arrondir, puis diviser par 2

si vous voulez le quart le plus proche, multipliez par 4, divisez par 4, etc.

Neil N
la source
16

Voici quelques méthodes que j'ai écrites qui seront toujours arrondies à n'importe quelle valeur.

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
la source
2

Il existe plusieurs options. Si les performances sont un problème, testez-les pour voir lequel fonctionne le plus rapidement dans une grande boucle.

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
la source
Cela devrait fonctionner, mais ce n'est tout simplement pas aussi élégant que certaines solutions proposées. Multiplier et utiliser la bibliothèque système est tout simplement sexy.
captncraig
La performance est généralement plus importante, et cela pourrait prendre moins de temps que les solutions de multiplication et de division.
John Fisher
3
Ce code n'est pas correct. Puisque l'arithmétique avec des doubles a généralement de petites erreurs d'arrondi, une opération telle que 4.8 - 4.0 pourrait donner par exemple 0.799999 .... Dans ce cas, le code ci-dessus serait arrondi à 4,5. Il serait également préférable d'utiliser Math.Floor au lieu de Math.Truncate, car pour le moment, les nombres négatifs ne sont pas arrondis correctement. Je préfère la réponse acceptée, car elle est plus simple et moins sujette aux erreurs de mise en œuvre.
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
la source
1

On dirait que vous devez arrondir au 0,5 près. Je ne vois aucune version de rounddans l'API C # qui fait cela (une version prend un certain nombre de chiffres décimaux pour arrondir, ce qui n'est pas la même chose).

En supposant que vous n'ayez à gérer que des nombres entiers de dixièmes, il suffit de calculer round (num * 2) / 2. Si vous utilisez des décimales arbitrairement précises, cela devient plus délicat. Espérons que non.

Paul Brinkley
la source
0

J'ai également eu des difficultés avec ce problème. Je code principalement en Actionscript 3.0 qui est le codage de base pour la plateforme Adobe Flash, mais il y a des similitudes dans les langues:

La solution que j'ai trouvée est la suivante:

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

C'est à peu près tout. Notez l'utilisation des «nombres» et des «entiers» et la façon dont ils sont traités.

Bonne chance!

Jason Henn
la source
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
la source
4
Ce code ne ressemble pas à C # comme souhaité dans la question. Qu'est ce que ça fait? Veuillez fournir une explication plutôt qu'un morceau de code dans une langue non spécifiée.
AdrianHHH
-1

La bonne façon de procéder est:

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

                return finalPrice;

            }
Carca
la source