Como faço para arredondar para o 0,5 mais próximo?

102

Tenho que exibir as avaliações e, para isso, preciso dos seguintes incrementos:

Se o número for 1,0 deve ser igual a 1
Se o número for 1,1 deve ser igual a 1
Se o número for 1,2 deve ser igual a 1
Se o número for 1,3 deve ser igual a 1,5
Se o número for 1,4 deve ser igual a 1.5
Se o número for 1.5 deve ser igual a 1.5
Se o número for 1.6 deve ser igual a 1.5
Se o número for 1.7 deve ser igual a 1.5
Se o número for 1.8 deve ser igual a 2.0
Se o número for 1.9 deve ser igual a 2.0
Se o número for 2.0 deve ser igual a 2.0
Se o número for 2.1 deve ser igual a 2.0
e assim por diante ...

Existe uma maneira simples de calcular os valores necessários?

Murtaza Mandvi
fonte
"e assim por diante ..." isso inclui números finitos próximos do valor máximo representável?
chux - Reintegrar Monica de

Respostas:

206

Multiplique sua classificação por 2, arredonde usando e Math.Round(rating, MidpointRounding.AwayFromZero), em seguida, divida esse valor por 2.

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

John Rasch
fonte
4
Não preciso digitar para manequins, preciso digitar para smarties
Neil N
3
Imperfeito! que tal estouro de inteiro! Você pode calcular apenas metade dos números inteiros possíveis.
Elazar Leibovich
2
@Elazar - se você pudesse ser classificado como 1.073.741.823º, não consigo pensar em um único caso de uso em que você se importaria se fosse "um bilhão um e meio" ou "um bilhão um" - se isso for realmente um problema então há algo inerentemente falho com o esquema de classificação :)
John Rasch
4
Divida primeiro, depois multiplique. Isso eliminará o problema de estouro e também permitirá arredondar para um número arbitrário.
Benjol
8
@Benjol, dividir primeiro e depois arredondar fará com que ele seja arredondado para o fator de 2 mais próximo, em vez do fator de metade. Incorreto.
Nacht
67

Multiplique por 2, arredonde e depois divida por 2

se você quiser o quarto mais próximo, multiplique por 4, divida por 4, etc.

Neil N
fonte
16

Aqui estão alguns métodos que escrevi que sempre arredondarão para cima ou para baixo para qualquer valor.

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
fonte
2

Existem várias opções. Se o desempenho for uma preocupação, teste-os para ver qual funciona mais rápido em um grande loop.

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
fonte
Isso deve funcionar, mas simplesmente não é tão elegante quanto algumas soluções fornecidas. Multiplicar e usar a biblioteca do sistema é simplesmente sexy.
captncraig
O desempenho geralmente é mais importante e isso pode levar menos tempo do que as soluções de multiplicação e divisão.
John Fisher
3
Este código não está correto. Uma vez que a aritmética com duplos geralmente tem alguns pequenos erros de arredondamento, uma operação como 4,8 - 4,0 poderia dar, por exemplo, 0,799999 .... Nesse caso, o código acima seria arredondado para 4.5. Também é melhor usar Math.Floor em vez de Math.Truncate, porque agora os números negativos não são arredondados corretamente. Prefiro a resposta aceita, porque é mais simples e menos sujeita a erros de implementação.
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
fonte
1

Parece que você precisa arredondar para o 0,5 mais próximo. Não vejo nenhuma versão roundna API C # que faça isso (uma versão leva um número de dígitos decimais para arredondar, o que não é a mesma coisa).

Supondo que você só precise lidar com números inteiros de décimos, é suficiente calcular round (num * 2) / 2. Se você estiver usando decimais arbitrariamente precisos, fica mais complicado. Esperemos que não.

Paul Brinkley
fonte
0

Eu também tive dificuldade com esse problema. Eu codifico principalmente em Actionscript 3.0, que é a codificação base para a plataforma Adobe Flash, mas existem semelhanças nas linguagens:

A solução que encontrei é a seguinte:

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

É basicamente isso. Observe o uso de 'Números' e 'Inteiros' e a maneira como são processados.

Boa sorte!

Jason Henn
fonte
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
fonte
4
Este código não se parece com C #, conforme desejado na pergunta. O que isso faz? Forneça alguma explicação em vez de apenas um pedaço de código em um idioma não especificado.
AdrianHHH
-1

A maneira correta de fazer isso é:

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

                return finalPrice;

            }
Carca
fonte