Perché ci sono così tanti tipi numerici (bit, int, float, double, long)?


9

Ho imparato PHP, Java e C. Ora sono curioso di sapere perché ci sono così tanti tipi di tipi di dati numerici come bit, int, float, double e long. Perché non creare un solo tipo per i numeri?

C'è qualche vantaggio in questo? Forse se usiamo numeri interi per contenere numeri così piccoli che possiamo risparmiare memoria?


6
Oltre alla risposta di HorusKol: i tipi 'float' e 'integer' sono intrinsecamente diversi. I float possono contenere numeri molto grandi, ma quando la dimensione del numero aumenta, la precisione diminuisce. Questa imprecisione è dovuta al modo in cui i float vengono memorizzati. Al contrario, l'intervallo di valori che è possibile memorizzare in un numero intero è piuttosto limitato, ma il valore è sempre esatto, quindi è possibile confrontare i valori molto più facilmente. Inoltre, ci sono due diversi tipi di comportamento con la divisione: gli interi 'troncano' automaticamente al numero intero più vicino, i float no. Ognuno di questi comportamenti è utile per diverse situazioni.
Kampu,

Javascript ha solo un tipo di numero in superficie.
Esailija,

@kampu: In realtà, in molte lingue, i numeri interi possono memorizzare qualsiasi numero purché la memoria (virtuale) sia abbastanza grande da rappresentarla.
Jörg W Mittag,

1
@ JörgWMittag: Tuttavia, l'interrogante parla chiaramente di linguaggi statici, non di linguaggi dinamici come Python, ad esempio. CPython stesso implementa l'intero "intervallo illimitato" come una matrice di ints a 32 bit, con il bit finale in ogni int usato per indicare se ci sono più bit da percorrere. Inoltre, i numeri interi possono memorizzare solo qualsiasi numero intero . Ciò significa che un float con memoria infinita può memorizzare valori nella precisione (infinity aleph one), mentre gli interi possono memorizzare valori solo nella precisione ( infinity aleph zero ).
Kampu,

@kampu: Poiché tutti i numeri sono rappresentati da una serie di bit, anche con memoria infinita, ci sarà sempre una mappatura uno a uno tra numeri in virgola mobile e numeri interi. Quindi non credo che uno venga messo in discussione.
VIENI DAL

Risposte:


17

Esistono due motivi per cui dovresti preoccuparti dei diversi tipi di dati numerici.

1. Salvataggio della memoria

for(long k=0;k<=10;k++)
{
    //stuff
}

Perché usare un lungo quando potrebbe essere altrettanto facilmente un numero intero o anche un byte? In questo modo risparmieresti diversi byte di memoria.

2. I numeri in virgola mobile e i numeri interi sono memorizzati in modo diverso nel computer

Supponiamo di avere il numero 22 memorizzato in un numero intero. Il computer memorizza questo numero in memoria in formato binario come:

0000 0000 0000 0000 0000 0000 0001 0110

Se non si ha familiarità con il sistema di numeri binari, questo può essere rappresentato in notazione scientifica come: 2 ^ 0 * 0 + 2 ^ 1 * 1 + 2 ^ 2 * 1 + 2 ^ 3 * 0 + 2 ^ 4 * 1 + 2 ^ 5 * 0 + ... + 2 ^ 30 * 0. L'ultimo bit può o non può essere utilizzato per indicare se il numero è negativo (a seconda che il tipo di dati sia firmato o non firmato).

In sostanza, è solo una somma di 2 ^ (bit place) * value.

Ciò cambia quando ci si riferisce a valori che coinvolgono un punto decimale. Supponiamo di avere il numero 3,75 in decimale. Questo è indicato come 11.11 in binario. Possiamo rappresentarlo come notazione scientifica come 2 ^ 1 * 1 + 2 ^ 0 * 1 + 2 ^ -1 * 1 + 2 ^ -2 * 1 o, normalizzato, come 1.111 * 2 ^ 2

Tuttavia, il computer non può memorizzarlo: non ha un metodo esplicito per esprimere quel punto binario (la versione del sistema di numeri binari del punto decimale). Il computer può memorizzare solo 1 e 0. Qui entra in gioco il tipo di dati in virgola mobile.

Supponendo che la dimensione di (float) sia di 4 byte, allora hai un totale di 32 bit. Al primo bit viene assegnato il "bit di segno". Non ci sono float o doppi non firmati. I successivi 8 bit sono usati per "l'esponente" e gli ultimi 23 bit sono usati come "significante" (o talvolta indicato come mantissa). Usando il nostro esempio 3.75, il nostro esponente sarebbe 2 ^ 1 e il nostro significato sarebbe 1.111.

Se il primo bit è 1, il numero è negativo. In caso contrario, positivo. L'esponente viene modificato da qualcosa chiamato "il bias", quindi non possiamo semplicemente archiviare "0000 0010" come esponente. Il bias per un numero in virgola mobile a precisione singola è 127 e il bias per una doppia precisione (è qui che il tipo di dati doppio prende il nome) è 1023. Gli ultimi 23 bit sono riservati per il significato. Il significato è semplicemente i valori a DESTRA del nostro punto binario.

Il nostro esponente sarebbe il bias (127) + esponente (1) o rappresentato in binario

1000 0000

Il nostro significato sarebbe:

111 0000 0000 0000 0000 0000

Pertanto, 3,75 è rappresentato come:

0100 0000 0111 0000 0000 0000 0000 0000

Ora diamo un'occhiata al numero 8 rappresentato come un numero in virgola mobile e come un numero intero:

0100 0001 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 1000

In che modo il computer aggiungerà 8.0 e 8? O anche moltiplicarli !? Il computer (più specificamente, i computer x86) ha diverse parti della CPU che aggiungono numeri in virgola mobile e numeri interi.


3
3) anche se raramente un problema: le operazioni su numeri più grandi delle dimensioni del computer sono più lente.
Loren Pechtel,

6

Prima di avere sistemi gigabyte (o su moderni sistemi embedded come Arduino), la memoria era un premio e quindi sono stati implementati metodi abbreviati per specificare quanta memoria occuperebbe un determinato numero - BIT è semplice - occuperebbe originariamente solo 1 bit di memoria.

Le altre dimensioni e nomi dei dati variano tra i sistemi. Su un sistema a 32 bit, INT (o MEDIUMINT) sarebbe generalmente di 2 byte, LONGINT sarebbe di 4 byte e SMALLINT sarebbe un singolo byte. I sistemi a 64 bit possono avere LONGINT impostato a 8 byte.

Anche ora - specialmente nelle applicazioni di database o nei programmi che hanno più istanze in esecuzione su server (come gli script lato server sui siti Web) - dovresti stare attento a ciò che scegli. Scegliere un numero intero largo 2, 4 o 8 byte per memorizzare valori compresi tra 0 e 100 (che può contenere un byte) è incredibilmente dispendioso se si dispone di una tabella di database con milioni di record.

Ulteriori informazioni: https://en.wikipedia.org/wiki/Integer_(computer_science)


bella risposta +1.
Vinay,

7
Non solo "indietro prima", ma anche "ora quando un sistema è piccolo". Su un dispositivo delle dimensioni di Arduino uno deve essere economico.
9000,

1
Quale sistema ha usato solo 1 bit per memorizzare un po '? i bit di solito non sono direttamente indirizzabili
jk.

1
questo è vero in molte architetture - ma i bit erano indirizzabili direttamente in sistemi molto vecchi e persino alcuni sistemi embedded più recenti (alcuni controller che avevo programmato solo 10 anni fa funzionavano con i bit - quelli avevano solo 64 posizioni indirizzabili di larghezze specifiche). Al giorno d'oggi, immagino che i compilatori lo risolvano e li inseriscano in array di byte.
HorusKol

Penso che il fattore principale sia la capacità e le prestazioni della CPU piuttosto che i problemi di memoria
James,

4

Oltre agli eccellenti punti di cpmjr123 sulla scarsità di memoria, sulla precisione e sui compromessi della gamma, questo è anche potenzialmente un compromesso della CPU.

Le macchine più moderne dispongono di hardware speciale per eseguire operazioni in virgola mobile chiamate FPU. Esistono anche sistemi che non dispongono di FPU (al giorno d'oggi si tratta in genere di piccoli dispositivi incorporati), di conseguenza, a seconda dell'hardware di destinazione, non dovresti utilizzare i tipi a virgola mobile o utilizzare una libreria software a virgola mobile. Anche se la tua macchina ha una FPU c'erano storicamente differenze nelle funzioni che poteva fornire. Qualsiasi funzione non svolta nell'hardware dovrebbe essere eseguita nel software (o evitata)

I calcoli in virgola mobile nel software vengono eseguiti eseguendo molte operazioni più semplici supportate dall'hardware. Pertanto, si ottiene anche un potenziale scambio di velocità.


4

Forse la cosa più importante è che ci sono davvero tre diversi tipi di numeri di base.

numero intero, decimale fisso e virgola mobile.

Si comportano tutti diversamente.

Una semplice operazione come 7/2 potrebbe fornire risposte di 3, 3,50 e 3,499 a seconda del tipo di dati utilizzato.

"fixed decimal" è il tipo di Cenerentola, è supportato nativamente solo in alcune lingue come COBOL e VisualBasic. È di scarso interesse per gli informatici, ma è vitale per chiunque invii una serie di conti o calcoli dell'imposta sulle vendite in una fattura.


Li separerei in modo diverso: numeri discreti, numeri approssimativi e avvolgimento di anelli algebrici. Tipici esempi in C sarebbe int, floate unsigned int, rispettivamente. I tipi a virgola fissa sono una sottocategoria di tipi discreti, ma gli anelli algebrici sono sostanzialmente diversi dai numeri [la confusione relativa ai tipi senza segno in C deriva dal fatto che si comportano principalmente come anelli piuttosto che numeri, ma non sono abbastanza coerenti] .
supercat,

3

C'è qualche vantaggio che ne fanno?

Ovviamente. Ci sono dei benefici. Nel mondo dei computer la memoria è una delle cose più importanti da considerare. A che serve avere una memoria di 2kb quando i dati possono contenere meno di 1kb? . Le ottimizzazioni dovrebbero essere lì. Se usi più memoria, ovviamente a un certo punto uccide la velocità del tuo computer. Ti piace davvero averlo? Nessun diritto...?

int - 2 bytes (16 bits)

long - 4 bytes (32 bits)

long long - 8 bytes (64 bits)

float - 4 bytes

Non solo la memoria ma esiste anche l'organizzazione del tipo di numeri. per un'istanza in virgola mobile. La precisione conta molto e ovviamente dovremmo avere un tipo che può darci più precisione.

Se consideriamo i vecchi tempi, avevamo una memoria molto minore, come potresti sapere. Per salvarlo e usarlo saggiamente abbiamo avuto queste differenze. E molto di più se vai avanti e provi a cercare con Google. Spero che questo aiuti.


3

numeri interi e reali (float, double) sono tipi concettualmente diversi con diversi insiemi di operazioni e proprietà intrinseche.

I numeri interi sono enumerabili ma i float no, ecc.

In effetti Float / double number è una struttura che combina due campi interi: mantissa ed esponente. I numeri complessi (che hai escluso dalla considerazione) sono ancora più, beh, complessi.

Qualsiasi linguaggio pratico dovrebbe avere almeno numeri interi e float come tipi distinti - operazioni troppo diverse su di essi.


Non ho familiarità con i "numeri complessi" che hai citato. Puoi spiegare ulteriormente?
cpmjr123,


Sono a conoscenza di numeri complessi sotto forma di + bi. Stavo chiedendo ulteriori informazioni su come il computer memorizza numeri complessi. Per quanto ne so, non ci sono tipi di dati primitivi che supportano questo.
cpmjr123,

I numeri complessi sono in genere memorizzati come due valori in virgola mobile, ovvero la loro a(parte reale) e b(parte immaginaria). La CPU in genere non implementa il supporto nativo per operazioni su numeri complessi, sebbene la CPU possa implementare istruzioni di aggiunta multipla accelerata per operazioni su coppie di valori, come (a b + c d) e (a b-c d).
rwong

1
Inoltre, molte lingue hanno alcuni tipi il cui comportamento è in gran parte definito come quello di un anello algebrico avvolgente (ad es. Se una variabile di tipo uint16_tcontiene 65535, aumentandola lo farà mantenere 0). Idealmente, le lingue dovrebbero avere tipi nettamente separati per rappresentare gli avvolgimenti di anelli e numeri algebrici (consentendo di intrappolare i numeri che traboccano, consentendo al codice di eseguire facilmente operazioni su cose che dovrebbero finire).
Supercat,

-1

Oltre al fatto che i tipi in virgola mobile si comportano in modo completamente diverso dai tipi interi, voglio dare un esempio più estremo del perché le dimensioni per numero contano davvero.

Immagina di voler ordinare un array (lungo). Ad esempio in C:

int numbers[100000000];

Quindi qui abbiamo 100 milioni di numeri.

Se ogni numero è lungo solo un byte (quindi usando al unsigned charposto di int), allora questo richiede 100 milioni di byte di spazio.

Se lo usi double, in genere sono 8 byte per numero, quindi 800 milioni di byte di spazio.

Quindi ogni volta che operi con molti oggetti (numeri in questo esempio), le dimensioni per oggetto (dimensioni per numero in questo esempio) contano davvero.

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.