Perché utilizzare altre basi numeriche durante la programmazione

35

I miei colleghi e io ci stiamo impegnando a capire perché qualcuno dovrebbe fare di tutto per programmare numeri in una base diversa dalla base 10.

Ho suggerito che potresti ottimizzare le equazioni più lunghe inserendo le variabili nella base corretta su cui stai lavorando (ad esempio, se hai solo serie di 5 di qualcosa senza resto, potresti usare la base 5), ma io Non sono sicuro che sia vero.

Qualche idea?

    
posta JMD 18.10.2012 - 21:06
fonte

16 risposte

59

La solita ragione per scrivere numeri, in codice, non in base alla base 10, è perché stai facendo un po 'di giocherellando.

Per scegliere un esempio in C (perché se C è valido per qualcosa, è buono per il bit-twiddling), ad esempio un formato di basso livello codifica un numero a 2 e un bit a 6 bit in un byte: xx yyyyyy :

main() {
    unsigned char codevalue = 0x94; // 10 010100
    printf("x=%d, y=%d\n", (codevalue & 0xc0) >> 6, (codevalue & 0x3f));
}

produce

x=2, y=20

In tale circostanza, scrivere le costanti in esadecimale è meno confuso di scriverle in decimale, perché una cifra esadecimale corrisponde esattamente a quattro bit (mezzo byte, un 'nibble') e due a un byte: il numero 0x3f ha tutti i bit impostati nel basso nibble e due bit impostati nel nibble alto.

Potresti anche scrivere quella seconda riga in ottale:

printf("x=%d, y=%d\n", (codevalue & 0300) >> 6, (codevalue & 077));

Qui, ogni cifra corrisponde a un blocco di tre bit. Alcune persone trovano più facile pensare, anche se penso che sia piuttosto raro in questi giorni.

    
risposta data 18.10.2012 - 18:56
fonte
45

Il motivo principale per cui utilizzo basi diverse è quando mi preoccupo dei bit.

È molto più semplice da leggere

int mask=0xFF;
byte bottom_byte = value & mask;

di

int mask=255;
byte bottom_byte = value & mask;

O immagine qualcosa di più complesso

int mask=0xFF00FF00;
int top_bytes_by_word = value & mask;

rispetto a

int mask=4278255360; //can you say magic number!? 
int top_bytes_by_word = value & mask;

È molto chiaro qui quale sia l'intento degli esempi esadecimali perché hex è fondamentalmente solo una forma più compatta di binario ... Al contrario, la base 10 (ciò che usiamo) non mappa quasi altrettanto bene in binario.

0xFF = b11111111 = 255
0xFFFF = b1111111111111111 = 65536
0xF0F0 = b1111000011110000 = 61680

Ci sono anche altre basi che puoi usare in alcune lingue. Troverai pochissimo uso di basi diverse da binario, esadecimale e decimale .. Alcune persone strane usano ancora l'ottale, ma questo è il più esoterico che vedrai in un programma sano.

    
risposta data 18.10.2012 - 21:21
fonte
8

Come probabilmente saprai, i computer sono basati su binari - questa è la base 2.

È facile convertire tra base 2 e 4, 8 e 16 (e multipli simili di 2), e mantenere questa traduzione nel codice sorgente può rendere molto più facile lavorare con i numeri motivo.

Per linguaggi di basso livello come Assembly e C, questo può tradurre direttamente nelle operazioni del processore (spostamento dei bit per divisione e moltiplicazione, ad esempio), il che significa che l'utilizzo di queste basi numeriche finisce con un codice molto più veloce.

Inoltre, non tutte le operazioni sono operazioni numeriche - ci sono mappe di bit in cui è necessario manipolare i bit direttamente - utilizzando una base 2 o uno dei multipli per fare ciò rende le operazioni molto più semplici.

Se desideri saperne di più, ti consiglio di leggere Codice di Charles Petzold .

    
risposta data 18.10.2012 - 21:11
fonte
6

Forse se stavi scrivendo un gioco che simula l'economia di alcune antiche civiltà che usa un sistema base 12

    
risposta data 18.10.2012 - 22:31
fonte
4

Al di fuori di programmi altamente specializzati, è piuttosto raro utilizzare basi diverse da 10, 16 o 2.

La base 16 (esadecimale) è utile semplicemente perché l'intera gamma di un byte (0-255) può essere rappresentata in due cifre (0x00-0xFF), il che può rendere molto più semplice il lavoro con i dump esadecimali grezzi o dati binari . Esadecimale è anche utile quando si usano maschere di bit con operatori bit a bit, perché le due cifre di una corrispondenza di byte aiutano la leggibilità.

Più raramente, la base 2 (binaria) può essere usata anche con operazioni bit a bit, ma molti linguaggi di programmazione non supportano letterali in base 2, e comunque esadecimale è molto più conciso e leggibile.

Anche la base 8 (ottale) viene talvolta utilizzata a causa delle autorizzazioni dei file UNIX. Oltre a questo, è piuttosto raro utilizzare basi diverse da 10 al di fuori di contesti matematici altamente specializzati.

    
risposta data 18.10.2012 - 21:16
fonte
3

Il motivo più comune valido per usare altre basi ha a che fare con la facilità di conversione alla base 2: è banale convertire un numero base-8 o un numero base-16 in binario senza usare una calcolatrice memorizzando una tabella breve di otto o sedici numeri:

 0000 0     0001 1     0010 2     0011 3
 0100 4     0101 5     0110 6     0111 7

 1000 8     1001 9     1010 A     1011 B
 1100 C     1101 D     1110 E     1111 F

Questo apre molteplici possibilità:

  • Quando un numero rappresenta una composizione di numeri binari significativi, è possibile determinare i singoli componenti senza un computer. Ad esempio, se un numero a 24 bit rappresenta un colore in RGB, è banale dire che 0xFF00FF è magenta (rosso + blu); l'attività è molto più difficile quando ti viene presentato 16711935
  • Quando un numero rappresenta un bit mask, è più pratico scriverlo come un numero esadecimale compatto, piuttosto che un numero binario molto più lungo
  • Alcune architetture facevano di tutto per rendere il loro codice binario di facile lettura quando venivano stampati come numeri ottali. PDP-11 era uno di questi sistemi: il bit più significativo consentiva di distinguere le operazioni a 8 bit da quelle a 16 bit; gli ultimi due gruppi ottali ti permetteranno di dire ai due registri coinvolti nell'operazione, e così via. Conoscevo diverse persone che potevano leggere il codice binario PDP-11 dallo schermo senza un disassemblatore, ma avevano bisogno che il codice macchina venisse stampato nel sistema ottale.
risposta data 18.10.2012 - 21:29
fonte
2

Il computer (o più esattamente il compilatore) non si preoccupa affatto di quale numero di basi si usa nel codice sorgente. I linguaggi di programmazione più comunemente usati supportano direttamente le basi 8 (ottale), 10 (decimale) e 16 (esadecimale). Alcuni inoltre supportano direttamente i numeri di base 2 (binari). Le lingue specializzate possono supportare anche altre basi numeriche. (Con "supporto diretto", intendo che consentono l'immissione di numeri in quella base senza ricorrere a trucchi matematici come bitshifting, moltiplicazione, divisione ecc. Nel codice sorgente stesso. Ad esempio, C supporta direttamente base-16 con la sua 0x numero prefisso e il normale set di cifre esadecimali di 0123456789ABCDEF. Ora, questi trucchi possono essere utili per rendere il numero più facile da capire nel contesto, ma finché si può esprimere lo stesso numero senza di essi, farlo - o no - è solo per comodità.)

Alla fine, tuttavia, questo è irrilevante. Diciamo che hai una frase simile a questa:

int n = 10;

L'intento è creare una variabile intera e inizializzarla con il numero decimale 10. Che cosa vede il computer?

i  n  t     n     =     1  0  ;
69 6e 74 20 6e 20 3d 20 31 30 3b (ASCII, hex)

Il compilatore lo renderizzerà e realizzerà che stai dichiarando una variabile di tipo int con il nome n , e assegnagli un valore iniziale. Ma qual è quel valore?

Al computer e ignorando i problemi di ordinamento e allineamento dei byte, l'input per il valore iniziale della variabile è 0x31 0x30 . Significa che il valore iniziale è 0x3130 (12592 in base 10)? Ovviamente no. Il parser della lingua deve continuare a leggere il file nella codifica dei caratteri utilizzata, quindi legge 1 0 seguito da un terminatore di istruzione. Dato che in questa base di lingua 10 si presume, questo legge (all'indietro) come "0 uno, 1 decine, fine". Ovvero, un valore di 10 decimale.

Se abbiamo specificato un valore in esadecimale e la nostra lingua utilizza 0x per specificare che il seguente valore è esadecimale, otteniamo quanto segue:

i  n  t     n     =     0  x  1  0  ;
69 6e 74 20 6e 20 3d 20 30 78 31 30 3b (ASCII, hex)

Il compilatore vede 0x (0x30 0x78) e riconosce che come prefisso di base-16, quindi cerca un numero di base-16 valido che lo segue. Fino al terminatore dell'istruzione, legge 10 . Questo si traduce in 0 "uno", 1 "sixteens", che funziona fino a 16 nella base 10. Oppure 00010000 nella base 2. O comunque ti piace rappresentarlo.

In entrambi i casi, ignorando le ottimizzazioni per motivi di semplicità, il compilatore assegna abbastanza spazio per contenere il valore di una variabile di tipo int e inserisce lì il valore letto dal codice sorgente in una sorta di variabile di attesa temporanea. Quindi (probabilmente molto più tardi) scrive i valori binari risultanti nel file codice oggetto.

Come vedi, il modo in cui scrivi valori numerici nel codice sorgente è completamente irrilevante. può avere un effetto molto lieve sui tempi di compilazione, ma immagino che (di nuovo, ignorando tali ottimizzazioni come la memorizzazione nella cache del disco da parte del sistema operativo) cose come turbolenze casuali intorno i piatti rotanti del disco, i tempi di accesso al disco, le collisioni del bus dati, ecc. hanno un effetto molto più grande.

In conclusione: non preoccuparti. Scrivi numeri in una base supportata dal tuo linguaggio di programmazione preferito e che ha senso per il modo in cui il numero verrà utilizzato e / o letto. Hai passato molto più tempo a leggere questa risposta di quanto tu non possa mai recuperare in tempi di compilazione, facendo attenzione a quale base numerica usare nel codice sorgente. ;)

    
risposta data 19.10.2012 - 14:15
fonte
1

why anyone would go out of their way to program numbers in a base other than base 10.

Ecco alcuni motivi che non sono ancora apparsi ...

x00 - Alcune API dei SO e dei dispositivi hardware si aspettano che gli argomenti siano in hex / binary. Quando si codifica per tali API, è più semplice utilizzare i numeri nello stesso formato previsto dall'API anziché convertirlo in basi diverse. Ad esempio, per inviare un byte di fine messaggio a un server o per inviare un messaggio per chiudere una connessione a un canale di comunicazione.

x01 - Potresti desiderare che la tua applicazione rappresenti caratteri non disponibili su determinate tastiere come il segno di copyright (\ u00a9).

x02 - Per mantenere costanti (visivamente) alcune costanti / letterali in diverse impostazioni di cultura, specialmente quando i codici / file sorgente vengono spostati tra gli sviluppatori con impostazioni locali diverse.

x03 - Per rendere il loro codice un aspetto confuso e complesso - La cosa buona è che C # non supporta le costanti ottali!

    
risposta data 18.10.2012 - 23:58
fonte
1

Il problema chiave è rappresentare una singola parola di dimensioni del computer in modo ragionevole. Il 6502 era un processore a 8 bit. Il 4004 era un processore a 4 bit.

Quando si ha a che fare con un numero a 4 o 8 bit, funziona bene. Un numero a 4 bit è un singolo carattere esadecimale. Un numero di 8 bit (un byte) è di due cifre esadecimali. I sistemi che hanno una potenza di una parola di 2 dimensioni sono oggi lo standard comunemente visto: 16 bit, 32 bit, 64 bit. Tutti questi dividono per 4 bene per la rappresentazione come esadecimale.

Ottale (base 8) è stato utilizzato in sistemi in cui la dimensione della parola era 12, 24 o 36. Il PDP8, l'IBM Mainframe e l'ICL 1900 di giorni precedenti usavano questi. Queste parole erano più facilmente rappresentate usando ottetti piuttosto che un intervallo limitato di esadecimali (sì, anche loro si dividono in 4).

Apparentemente c'era anche un risparmio sui costi usando la numerazione di base 8. Rappresentando 12 bit in BCD, la prima cifra può essere solo 0-4 ma la seconda, la terza e la quarta possono essere 0-9. Se questo è stato fatto come esadecimale, uno ha 3 caratteri esadecimali, ma ognuno ha 16 valori possibili. Era meno costoso produrre un tubo nixie che aveva solo 0-7 di uno che aveva 0-9 (con logica aggiuntiva per BCD) o 0-F per esadecimale.

Si vede ancora oggi l'ottale con i permessi del file unix (755, 644) dove proprietario, gruppo e mondo hanno ciascuno 3 bit che rappresentano i permessi.

Nel mondo della matematica, occasionalmente si fanno cose strane con basi diverse. Ad esempio, una sequenza Goodstein debole da progetto euler 396 ... o qualcosa di più semplice con numeri palindromici . Esiste la proprietà di un numero in base N che un numero che è un multiplo di N - 1 sarà avere le sue cifre riassumere in un multiplo di N - 1 . Inoltre, se N - 1 è un quadrato perfetto, questa proprietà esiste anche per sqrt ( N - 1 ) . Questo ha alcune applicazioni in alcuni problemi matematici.

    
risposta data 19.10.2012 - 00:35
fonte
1

Nel settore finanziario esiste uno schema identificativo che è effettivamente base 36 . Utilizza i numeri 0-9 e le lettere B-Z per rappresentare le cifre da 0 a 35. Salta le vocali per impedire la generazione di nomi fastidiosi.

Tuttavia, non è perfetto. C'è stato un tempo in cui una sfortunata compagnia aveva l'id B000BZ .

    
risposta data 19.10.2012 - 15:04
fonte
1

Motivo n. 1: perché tutti i numeri a livello di circuito sono rappresentati nella base 2 (l'interruttore elettrico è acceso o spento). Motivo n. 2: poiché a un livello più alto dei circuiti effettivi, i bit sono raggruppati in byte e i byte possono essere facilmente rappresentati come due cifre esadecimali, quando impiegherebbero 3 cifre decimali (e alcune convalide) per rappresentare tutti i possibili valori del byte.

Quindi, se stai lavorando a questi livelli (o approssimandoli, in qualche ambiente gestito), è più facile lavorare in binario o esadecimale che decimale. Le situazioni in cui lo faresti sono varie, ma in genere non sono mai situazioni in cui hai solo bisogno di aritmetica di base.

    
risposta data 19.10.2012 - 18:16
fonte
1

Un'area in cui i numeri di base 16 (esadecimali) sono usati molto frequentemente è nel specificare il colore, specialmente quando si utilizza HTML / CSS per il web. I colori che usiamo sui display digitali sono specificati usando una combinazione di 3 valori di intensità per 3 colori "base" (RGB - rosso, verde, blu) che vengono mescolati insieme per creare uno dei 16 milioni di colori visualizzabili (usando colori a 24 bit ).

Ad esempio, il verde a intensità piena in esadecimale sarebbe 0x00ff00 e 65280 in decimale. Ora immagina di provare a "manualmente" mescolare un colore nella tua testa che ha parti uguali rosso e blu, diciamo a metà intensità, per creare un bel viola :) In esadecimale questo sarebbe scritto semplicemente come 0x800080 mentre il valore decimale per questo sarebbe 8388736 . Diventa ancora più semplice quando lavori con sfumature di grigio: 50% grigio è 0x808080 (hex) e 8421504 (decimale), 75% è 0xC0C0C0 e 12632256 , e così via.

Usare hex è molto più intuitivo e chiunque abbia familiarità con questo uso del colore sarà immediatamente in grado di "indovinare" il colore semplicemente osservando il valore esadecimale. È anche molto meno soggetto ad errori se è necessario utilizzare lo stesso colore più volte (che di solito è il caso).

Controlla qualsiasi pagina web (e in particolare il CSS) per una quantità pazzesca di utilizzo di esagoni: D

NOTA: nei CSS i valori esadecimali vengono scritti utilizzando un prefisso # , ad esempio: #00ff00 per il verde e talvolta anche abbreviato a solo tre cifre, ad esempio #0f0 per il verde.

    
risposta data 24.10.2012 - 09:12
fonte
0

Per alcuni algoritmi, la base 2 ha più senso di ogni altra cosa. Ad esempio, preferiresti scrivere una funzione per attraversare un albero binario o un albero 10-ary?

Ma, più frequentemente, viene usata la base 2 perché è così che i computer rappresentano quasi universalmente i loro numeri. Ciò significa che:

  • molte operazioni sono più efficienti in base 2:
    • i poteri di moltiplicazione, divisione e modulo di 2 sono molto più veloci della divisione generale
    • flags e piccoli valori possono essere memorizzati, recuperati e manipolati in modo più efficiente come cifre binarie di un numero più grande.
  • Le operazioni
  • che leggono, scrivono e manipolano i file di dati e i flussi di dati di rete devono trattare direttamente il fatto che sono rappresentati come numeri binari.

Inoltre, c'è sempre la rara applicazione che richiede intrinsecamente una base dispari che potrebbe non essere né 2 né 10.

    
risposta data 18.10.2012 - 21:23
fonte
0

È una preferenza sincera, se per qualche motivo hai polidattilia e hai 11 dita o contate con le dita dei piedi così ti piace lavorare in base 20 è onestamente da te. Ma renditi conto che su un argomento di universalità che la maggior parte di noi che ha a che fare con bit e byte su base giornaliera sarà davvero segnato se otteniamo qualcosa che sta facendo manipolazione di bit in base 19.

RAGIONI PER BASE x

Base 10 - Modello di tutte le nostre cose perché abbiamo 10 cifre di conteggio (i piedi sono strani e maleodoranti quindi non li usiamo)

Base 2 - I computer usano questo per bit (on / off) questo è correlato a livelli di tensione leggibili propagati da gate / transistor / condensatori.

Base 8 - Vecchio, indietro quando i computer non erano super enormi (o indietro quando erano spaziosi) questo andava bene per qualcosa o altro (non mi piace un po ')

Base 16 - Buono per mostrare i bocconcini superiore e inferiore di un byte per la manipolazione dei bit. Questo è super utile nel mondo embedded / fpga / hardware.

BASI NORMALI IN COMPUTER

Per andare con le preferenze, potrei dirti esattamente come "on" un colore è in un esadecimale il valore RGB che mi è stato dato, questo di conseguenza può essere rappresentato in un singolo int in hardware e quindi con alcuni turni può essere dato torna a me easy-peasy, 1 colore complesso = 1 punto dati che è bello per l'elaborazione di immagini di grandi dimensioni con memoria limitata. Confrontalo con una rappresentazione di base 10, potresti aggiungerli tutti e memorizzarli in un numero, ma quale numero è, o forse R è tempo 10000, G è 100, e B è il suo spazio, sono molte operazioni matematiche , di solito le moltiplicazioni costano più cicli di un turno, quindi il tuo prossimo pezzo di dati è già in coda prima che tu abbia finito con l'ultimo pezzo in elaborazione, whoops, non c'è più.

A volte è meglio lavorare in base 2, 8 o 16. Con la maggior parte delle macchine un multiplo per 2 è solo un po 'di shift, quelle sono super veloci, lo stesso con una divisione per 2.

Per esporre ulteriormente l'idea del bit twiddling. Ci sono un gran numero di volte quando si lavora in un ambiente embedded che ho bisogno di accedere ad alcuni array di luci, interruttori o altri elementi mappati al registro.

In questo caso l'assegnazione di un intero char, byte o int a ciascun interruttore sarebbe sia inefficiente e sciocco, un interruttore o una luce ha 2 posizioni - on e off - perché dovrei assegnare qualcosa che ha fino a 256 posizioni, o 2 ^ 16 posizioni, ecc. Ogni luce di un array può essere a 1 bit 8 o 16 o 32 o 64 o 128 (larghezza del tipo di dati) su una singola parola / registro. L'efficienza dello spazio è necessaria e piuttosto gradita.

Usando tutto ciò che è di base nella programmazione per cose come gestire i dati RGB, molti dati di segnale - GPS, audio, ascii, ecc. - sono molto più semplici in esadecimale, binario e ottale poiché è così che viene rappresentato nella macchina e si può più facilmente discernere cosa viene presentato e come manipolarlo.

USING STRANGE BASES

Non c'è efficienza a meno che non si scriva per questo. Vuoi la base 11, devi impostare un tipo di dati per esso e sovraccaricare qualsiasi operatore per gestirne la rappresentazione all'utente. Non vedo alcun motivo per cui un sistema che contiene 5 articoli e che abbia mai solo multipli di 5 articoli debba essere convertito nella matematica dei cinque elementi. E inoltre, è meglio che preghi che chiunque abbia deciso di scrivere il proprio codice per la base 271 lo abbia documentato bene o si possa dedicare più tempo alla comprensione di quanto valga la pena creare la base 271 perché tutti gli elementi sono multipli di 271.

    
risposta data 20.10.2012 - 00:19
fonte
0

Nei vecchi tempi dei computer, avevamo un numero di display che mostrava le cifre 0-9, ma non avevamo ancora A-F.

Il collegamento è uno di questi esempi ...

Octal si adattava perfettamente a questi display ed era più facile di binario o decimale.

    
risposta data 20.10.2012 - 01:48
fonte
0

Sono sorpreso che tutte le altre risposte non abbiano menzionato due usi molto comuni nell'elaborazione di basi alternative:

  1. Codifica : la codifica Base64 ad esempio è estremamente comune. La codifica interpreta semplicemente una serie di byte come un grande numero binario (base-2) e converte quel numero in un numero Base64 rappresentato da cifre ASCII.
  2. Compressione : spesso è desiderabile rappresentare un numero binario, decimale o esadecimale in una base più grande per abbreviare la rappresentazione. Ad esempio, tutti i bit shortener come bit.ly lo stanno facendo. Oppure potresti farlo per abbreviare un GUID da utilizzare in un URL.

    - 821F6321-881B-4492-8F84-942186DF059B (base-16 guid) 
    becomes
    - RRIDHW463YD8YXX7MIDI (base-36)
    - 3UFmaWDjj9lifYyuT0 (base-62)
    
risposta data 29.08.2016 - 22:04
fonte

Leggi altre domande sui tag