Il modo migliore per ottenere una parte intera di un numero decimale


89

Qual è il modo migliore per restituire l'intera parte numerica di un decimale (in c #)? (Questo deve funzionare per numeri molto grandi che potrebbero non rientrare in un int).

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

Lo scopo di questo è: sto inserendo in un campo decimale (30,4) nel db e voglio assicurarmi di non provare a inserire un numero troppo lungo per il campo. Determinare la lunghezza dell'intera parte numerica del decimale fa parte di questa operazione.


Non puoi ottenere la parte int; puoi ottenere la parte intera del numero e abbandonare la parte frazionaria. La parte intera del numero di un Decimal può facilmente superare un int e lanciare o avvolgere, uccidendo silenziosamente il tuo codice.

1
Bene, ecco perché questa domanda non è così semplice come sembra. Ho bisogno che funzioni per numeri molto grandi con la stessa affidabilità che funziona per numeri piccoli. Tuttavia, "numero intero" è più accurato di "int" - riformulerò sopra.
— Yaakov Ellis

Risposte:


212

A proposito ragazzi, (int) Decimal.MaxValue andrà in overflow. Non è possibile ottenere la parte "int" di un decimale perché il decimale è troppo grande per essere inserito nella casella int. Appena controllato ... è anche troppo grande per molto tempo (Int64).

Se vuoi il bit di un valore Decimale a SINISTRA del punto, devi farlo:

Math.Truncate(number)

e restituisce il valore come ... DECIMAL o DOUBLE.

modifica: Truncate è sicuramente la funzione corretta!


Quindi il risultato è decimale o doppio che non avrà mai nulla dopo il punto ma non c'è un oggetto integrato per memorizzare il risultato come un "int" (senza cifre decimali) che sembra un po 'noioso?
— Coops

@CodeBlend: non c'è molto bisogno di progettare framework attorno al desiderio di perdere precisione.

@ CodeBlend: perderesti comunque la precisione perché stai tagliando i valori decimali di un numero. Non sono sicuro di cosa stai ottenendo.

Non sono sicuro che funzionerà o no. Perché Math.Truncate (-5,9999999999999999999) restituisce -6,0 per me ... !!
— Bharat Mori

@Bharat Mori: Sembra che -5,99999999999999999 sia arrotondato a -6,0 prima del troncamento. Prova con il suffisso "m" e funzionerà. Math.Truncate (-5,9999999999999999999m) restituisce -5.
— Henry


4

Dipende da cosa stai facendo.

Per esempio:

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

L'impostazione predefinita è sempre la prima, il che può essere una sorpresa ma ha molto senso .

Il tuo cast esplicito farà:

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

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

Dal modo in cui hai formulato la domanda sembra che questo non sia quello che vuoi - lo vuoi pavimentare ogni volta.

Farei:

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

Controlla anche le dimensioni del tuo decimal: possono essere abbastanza grandi, quindi potrebbe essere necessario utilizzare un file long.


(lungo) Decimal.MaxValue overflow.

Punto giusto: immagino che sia per questo che Math.Truncate (decimal) restituisce decimal.
— Keith

In C #, il casting a int non viene arrotondato, quindi (int) 0.6f sarà 0 e (int) 343564565.5 terminerà con 5, non 6. Prova qui: repl.it/repls/LuxuriousCheerfulDistributeddatabase
— sschmidTU

0

Devi solo lanciarlo, come tale:

int intPart = (int)343564564.4342

Se vuoi ancora usarlo come decimale nei calcoli successivi, allora Math.Truncate (o forse Math.Floor se vuoi un certo comportamento per i numeri negativi) è la funzione che desideri.


5
Questo è sbagliato sbagliato sbagliato. Se il risultato è maggiore di quello che può contenere un Int32, genererà un'eccezione o (anche peggio !!!) traboccerà silenziosamente e si riavvolgerà, dandoti un risultato completamente errato senza che tu lo sappia.

2
No, non è sbagliato . Molti non sono validi per valori decimali / virgola mobile molto grandi, ma va benissimo per la maggior parte delle situazioni. I numeri sono molto spesso limitati per essere sufficientemente bassi durante la codifica, quindi questo non deve essere un problema. Inoltre, ho fornito una soluzione Math.Truncate che funziona per tutti i valori.
— Noldorin

2
Capisco perché sei incazzato con me. Il fatto è che la tua risposta è sbagliata. Gli stai dicendo di correre il rischio che non si rompa perché, ehi, molti numeri sono piccoli. È un rischio sciocco da prendere. Dovresti modificare la tua risposta e rimuovere tutto tranne Math.Truncate poiché è l'unica parte corretta.

1
Sai cosa dicono di ASSUME. Inoltre, la tua ipotesi è particolarmente orribile. È infiammatorio? Immagino che tu possa dirlo. Puoi anche dire che dire a qualcuno di fare qualcosa di sciocco che gli causerà problemi lungo la strada è anche infiammatorio, se non addirittura immorale.

1
In effetti sarebbe sbagliato se intendessi dare una risposta fuorviante. Per così dire, stavo semplicemente cercando di aiutare. Se sono colpevole di un leggero malinteso o di non apprezzare appieno la domanda, è abbastanza giusto: non è un crimine. Allora perché stiamo litigando adesso? Siamo tutti d'accordo che Truncate è la risposta giusta.
— Noldorin

0

Un modo molto semplice per separare il valore e il valore della sua parte frazionaria.

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

s è una parte frazionaria = 5 e
i è il valore intero = 3


1
Vedi la risposta in alto sopra. Questo non funziona perché (int)Decimal.MaxValuetraboccherà.
— Yaakov Ellis

0

Spero di aiutarti.

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

-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

1
La risposta accettata, pubblicata più di otto anni fa, spiega perché questa risposta è sbagliata. L'intervallo di decimalè molto maggiore di quello di int. Inoltre, questa non è una domanda VB.
— Joe Farrell

@ JoeFarrell - se ritieni che la risposta sia sbagliata, potresti prendere in considerazione la possibilità di votarla negativamente oltre a lasciare un commento sull'effetto. Tuttavia, non contrassegnarlo (non che io dica che lo hai) È un tentativo di rispondere alla domanda. Potrebbe essere nella lingua sbagliata, potrebbe essere sbagliato anche in VB, ma è un tentativo. Vedi, ad esempio, " Quando una risposta risponde alla domanda sbagliata, non è una risposta? ".
— Wai Ha Lee
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.