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.