¿Cómo redondeo al 0,5 más cercano?

102

Tengo que mostrar calificaciones y para eso necesito incrementos de la siguiente manera:

Si el número es 1.0 debería ser igual a 1
Si el número es 1.1 debería ser igual a 1
Si el número es 1.2 debería ser igual a 1
Si el número es 1.3 debería ser igual a 1.5
Si el número es 1.4 debería ser igual a 1.5
Si el número es 1.5 debe ser igual a 1.5
Si el número es 1.6 debe ser igual a 1.5
Si el número es 1.7 debe ser igual a 1.5
Si el número es 1.8 debe ser igual a 2.0
Si el número es 1.9 debe ser igual a 2.0
Si el número es 2.0 debe ser igual a 2.0
Si el número es 2.1 debe ser igual a 2.0
y así sucesivamente ...

¿Existe una forma sencilla de calcular los valores requeridos?

Murtaza Mandvi
fuente
"y así sucesivamente ..." ¿incluye eso números finitos cercanos al valor máximo representable?
chux - Reincorporar a Monica

Respuestas:

206

Multiplique su calificación por 2, luego redondee usando Math.Round(rating, MidpointRounding.AwayFromZero), luego divida ese valor por 2.

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

John Rasch
fuente
4
No necesito escribir para tontos, necesito escribir para inteligentes
Neil N
3
¡No es perfecto! ¿Qué pasa con el desbordamiento de enteros? Puede calcular solo la mitad de los números enteros posibles.
Elazar Leibovich
2
@Elazar: si pudieras estar clasificado tan alto como 1.073.741.823, no puedo pensar en un solo caso de uso en el que te importaría si es "mil millones uno y medio" o "mil millones uno", si eso es realmente un problema entonces hay algo inherentemente defectuoso con el esquema de clasificación :)
John Rasch
4
Dividir primero, luego multiplicar. Esto eliminará el problema de desbordamiento y también le permitirá redondear a un número arbitrario.
Benjol
8
@Benjol, dividir primero y luego redondear hará que se redondee al factor más cercano de 2, en lugar de al factor de la mitad. Incorrecto.
Nacht
67

Multiplica por 2, redondea y luego divide por 2

si quiere el cuarto más cercano, multiplique por 4, divida por 4, etc.

Neil N
fuente
16

Aquí hay un par de métodos que escribí que siempre se redondearán hacia arriba o hacia abajo a cualquier 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
fuente
2

Hay varias opciones. Si el rendimiento es un problema, pruébelos para ver cuál funciona más rápido en un ciclo grande.

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
fuente
Esto debería funcionar, pero no es tan elegante como algunas soluciones. Multiplicar y usar la biblioteca del sistema es simplemente sexy.
captncraig
El rendimiento suele ser más importante, y esto podría terminar tomando menos tiempo que las soluciones de multiplicación y división.
John Fisher
3
Este código no es correcto. Dado que la aritmética con dobles generalmente tiene algunos pequeños errores de redondeo, una operación como 4.8 - 4.0 podría dar, por ejemplo, 0.799999 .... En este caso, el código anterior se redondearía a 4.5. También sería mejor usar Math.Floor en lugar de Math.Truncate, porque en este momento los números negativos no se redondean correctamente. Prefiero la respuesta aceptada, porque es más simple y menos propensa a errores de implementación.
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
fuente
1

Parece que necesitas redondear al 0,5 más cercano. No veo ninguna versión de rounden la API de C # que haga esto (una versión requiere un número de dígitos decimales para redondear, que no es lo mismo).

Suponiendo que solo tiene que lidiar con números enteros de décimas, es suficiente para calcular round (num * 2) / 2. Si está utilizando decimales arbitrariamente precisos, se vuelve más complicado. Esperemos que no.

Paul Brinkley
fuente
0

También tuve dificultades con este problema. Yo codifico principalmente en Actionscript 3.0 que es codificación base para la plataforma Adobe Flash, pero hay simularidades en los idiomas:

La solución que se me ocurrió es la siguiente:

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

Eso es practicamente todo. Tenga en cuenta el uso de 'números' y 'enteros' y la forma en que se procesan.

¡Buena suerte!

Jason Henn
fuente
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
usuario2260011
fuente
4
Este código no se parece a C # como se quería en la pregunta. ¿Qué hace? Proporcione una explicación en lugar de solo un fragmento de código en un idioma no especificado.
AdrianHHH
-1

La forma correcta de hacer esto es:

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

                return finalPrice;

            }
Carca
fuente