La mejor manera de obtener parte de un número entero de un número decimal

89

¿Cuál es la mejor manera de devolver la parte entera de un decimal (en c #)? (Esto tiene que funcionar para números muy grandes que pueden no encajar en un int).

GetIntPart(343564564.4342) >> 343564564
GetIntPart(-323489.32) >> -323489
GetIntPart(324) >> 324

El propósito de esto es: Estoy insertando en un campo decimal (30,4) en la base de datos y quiero asegurarme de no intentar insertar un número que sea demasiado largo para el campo. La determinación de la longitud de la parte entera del decimal es parte de esta operación.

Yaakov Ellis
fuente
No puede obtener la parte int; puede obtener la parte del número entero y deshacerse de la parte fraccionaria. Toda la parte numérica de un decimal puede desbordar fácilmente un int y lanzar o envolver, matando silenciosamente su código.
1
Bueno, por eso esta pregunta no es tan simple como parece. Necesito que esto funcione para números muy grandes de manera tan confiable como lo hace para números pequeños. Sin embargo, "número entero" es más exacto que "int"; lo reformularé anteriormente.
Yaakov Ellis

Respuestas:

212

Por cierto chicos, (int) Decimal.MaxValue se desbordará. No puede obtener la parte "int" de un decimal porque el decimal es demasiado grande para ponerlo en el cuadro int. Recién comprobado ... es demasiado grande durante mucho tiempo (Int64).

Si desea que el bit de un valor decimal esté a la IZQUIERDA del punto, debe hacer esto:

Math.Truncate(number)

y devuelve el valor como ... A DECIMAL o DOBLE.

editar: ¡Truncar es definitivamente la función correcta!


fuente
Entonces, ¿el resultado es decimal o doble que nunca tendrá nada después del punto, pero no hay un objeto integrado para almacenar el resultado como un "int" (sin lugares decimales) que parece un poco escaso?
Coops
@CodeBlend: No hay mucha necesidad de diseñar marcos en torno al deseo de perder precisión.
@CodeBlend: aún perdería precisión porque está cortando los valores decimales de un número. No estoy seguro de a qué te refieres.
No estoy seguro de que esto funcione o no. ¡Porque Math.Truncate (-5.99999999999999999) devuelve -6.0 para mí ... !!
Bharat Mori
@Bharat Mori: Parece que -5,99999999999999999 se redondea a -6,0 antes del truncado. Prueba con el sufijo "m" y funcionará. Math.Truncate (-5.99999999999999999m) da -5.
Henry
4

Depende de lo que estés haciendo.

Por ejemplo:

//bankers' rounding - midpoint goes to nearest even
GetIntPart(2.5) >> 2
GetIntPart(5.5) >> 6
GetIntPart(-6.5) >> -6

o

//arithmetic rounding - midpoint goes away from zero
GetIntPart(2.5) >> 3
GetIntPart(5.5) >> 6
GetIntPart(-6.5) >> -7

El valor predeterminado es siempre el primero, lo que puede ser una sorpresa, pero tiene mucho sentido .

Tu elenco explícito servirá:

int intPart = (int)343564564.5
// intPart will be 343564564

int intPart = (int)343564565.5
// intPart will be 343564566

Por la forma en que ha redactado la pregunta, parece que esto no es lo que quiere, quiere decirlo todo el tiempo.

Yo lo haría:

Math.Floor(Math.Abs(number));

También verifique el tamaño de su decimal; pueden ser bastante grandes, por lo que es posible que deba usar un archivo long.

Keith
fuente
(largo) Decimal.MaxValue se desborda.
Punto justo: supongo que es por eso que Math.Truncate (decimal) devuelve decimal.
Keith
En C #, la conversión a int no se redondea, por lo que (int) 0.6f será 0, y (int) 343564565.5 terminará en 5, no en 6. Pruebe aquí: repl.it/repls/LuxuriousChertherDistributeddatabase
sschmidTU
0

Solo necesitas lanzarlo, como tal:

int intPart = (int)343564564.4342

Si aún desea usarlo como decimal en cálculos posteriores, entonces Math.Truncate (o posiblemente Math.Floor si desea un cierto comportamiento para números negativos) es la función que desea.

Noldorin
fuente
5
Esto está mal, mal, mal. Si el resultado es mayor de lo que puede contener un Int32, lanzará una excepción o (¡¡¡lo que es peor !!!) se desbordará silenciosamente y se reiniciará, lo que le dará un resultado completamente incorrecto sin que usted lo sepa.
2
No, no está mal . Es posible que no sea válido para valores decimales / de coma flotante muy grandes, pero está perfectamente bien para la mayoría de las situaciones. A menudo, los números se limitan a ser lo suficientemente bajos al codificar, por lo que esto no tiene por qué ser un problema. Además, proporcioné una solución Math.Truncate que funciona para todos los valores.
Noldorin
2
Veo por qué estás enojado conmigo. El hecho es que tu respuesta es incorrecta. Le estás diciendo que se arriesgue a que no se rompa porque, oye, muchos números son pequeños. Es un riesgo tonto. Debes editar tu respuesta y eliminar todo menos Math.Truncate ya que es la única parte correcta.
1
Sabes lo que dicen sobre ASSUME. Además, su suposición es particularmente terrible. ¿Eso es inflamatorio? Supongo que podrías decir eso. También puede decir que decirle a alguien que haga algo tonto que le causará problemas en el futuro también es inflamatorio, si no totalmente poco ético.
1
De hecho, estaría mal si tuviera la intención de dar una respuesta engañosa. Por así decirlo, simplemente estaba tratando de ayudar. Si soy culpable de un leve malentendido o de no apreciar completamente la pregunta, es bastante justo: no es un delito. Entonces, ¿por qué estamos discutiendo ahora? Todos estamos de acuerdo en que Truncar es la respuesta correcta.
Noldorin
0

Manera muy fácil de separar el valor y su valor de parte fraccional.

double  d = 3.5;
int i = (int)d;
string s = d.ToString();
s = s.Replace(i + ".", "");

s es una parte fraccionaria = 5 e
i es un valor entero = 3

Amit Gohel
fuente
1
Vea la respuesta principal arriba. Esto no funciona porque (int)Decimal.MaxValuese desbordará.
Yaakov Ellis
0

Espero ayudarte.

/// <summary>
/// Get the integer part of any decimal number passed trough a string 
/// </summary>
/// <param name="decimalNumber">String passed</param>
/// <returns>teh integer part , 0 in case of error</returns>
private int GetIntPart(String decimalNumber)
{
    if(!Decimal.TryParse(decimalNumber, NumberStyles.Any , new CultureInfo("en-US"), out decimal dn))
    {
        MessageBox.Show("String " + decimalNumber + " is not in corret format", "GetIntPart", MessageBoxButtons.OK, MessageBoxIcon.Error);
        return default(int);
    } 

    return Convert.ToInt32(Decimal.Truncate(dn));
}
luka
fuente
-2
   Public Function getWholeNumber(number As Decimal) As Integer
    Dim round = Math.Round(number, 0)
    If round > number Then
        Return round - 1
    Else
        Return round
    End If
End Function
Mattheu Norwood
fuente
1
La respuesta aceptada, publicada hace más de ocho años, explica por qué esta respuesta es incorrecta. El rango de decimales mucho mayor que el de int. Además, esta no es una pregunta de VB.
Joe Farrell
@JoeFarrell: si cree que la respuesta es incorrecta, podría considerar rechazarla además de dejar un comentario al respecto. Sin embargo, no lo marques (no es que esté diciendo que lo hayas hecho). Es un intento de responder a la pregunta. Puede que esté en el idioma incorrecto, puede que sea incorrecto incluso en VB, pero es un intento. Consulte, por ejemplo, " Cuando una respuesta responde a una pregunta incorrecta, ¿no es una respuesta? ".
Wai Ha Lee