Notazione scientifica efficiente


12

L'altro giorno il mio insegnante di chimica ci stava spiegando della notazione scientifica (usando un piccolo numero e moltiplicandolo per poteri di dieci per esprimere più facilmente un gran numero), il che mi ha riportato indietro di alcuni anni a quando l'ho imparato per la prima volta. Dopo aver appreso le nozioni di base, avevamo fatto una serie di domande matematiche tipiche, alcune delle quali erano le seguenti:

Rappresenta quanto segue in notazione scientifica:
a) 50000000
b) 120000000000000
c) 9000000000000000000000000000000000000000
d) pi ^ e ^ i ^ j ^ k ^ std :: vector
...
z) 200
...

E ho pensato: "Cosa? Ci è stato detto che la notazione scientifica è stata usata per rendere più efficiente la scrittura di grandi numeri, ma alcuni casi non sono affatto più efficienti!"

Considera il numero

300

e la sua rappresentazione in notazione scientifica:

3x10^2

Cosa, la versione scientificamente notata occupa effettivamente più spazio? Non possiamo averlo adesso, vero? (Lo spazio sullo schermo è prezioso.)
Potremmo determinare noi stessi se è più efficiente nello spazio scrivere un numero in notazione scientifica o no, oppure ...

Compito

Il tuo programma o funzione dovrebbe assumere come input un singolo numero positivo ndi dimensioni arbitrarie (fino a ciò che la tua lingua supporta) e produrre la versione scientificamente notata del numero.
Tuttavia, se il numero originale n, dopo la rimozione degli zeri finali e del decimale finale, richiede meno o la stessa quantità di caratteri da visualizzare rispetto alla sua versione notata scientificamente, è necessario invece generare quel numero originale n.

Il codice deve essere il più breve possibile perché anche l'output deve essere il più breve possibile.

specificazioni

La notazione scientifica efficiente è definita come segue:

bx10^e

bè il numero di input opportunamente diviso per poteri di 10 tali che 1 <= b < 10. Questo numero deve avere tutti gli zero finali (e il punto decimale, se necessario) rimossi, ma deve avere la precisione del numero originale (fino al limite del punto decimale nella tua lingua, ovviamente). Cioè 90000diventa 9, 13.500diventa 1.35, 0.000675diventa 6.75ecc. Se questo numero finisce per contenere più cifre decimali di quante la tua lingua possa gestire, dovrebbe essere arrotondato al numero massimo di posizioni decimali.

eè l'esponente a cui dieci viene elevato in modo tale n = b x 10^e(ricordare che questo numero deve essere negativo se nè inferiore a 1). Questo numero non dovrebbe avere zeri finali o un decimale (principalmente perché se non è un numero intero qualcosa non va ...).

I caratteri x10^ devono rimanere come nella stringa tra be e.

Casi test

Input -> output
1 -> 1
20 -> 20
3000000 -> 3x10^6
400000 -> 400000
0.008093 -> 0.008093
0.007835000000000 -> 0.007835
0.000003000000 -> 3x10^-6
0.00000065 -> 6.5x10^-7
0 -> 0

punteggio

Questo è , quindi vince il codice più breve in byte.

Altre regole e chiarimenti

  • Gli zeri finali (e / o il punto decimale finale) non vengono conteggiati nel conteggio dei caratteri del numero di input originale n. Tienilo a mente per casi come il test case 6
  • Si può presumere che se il numero di input è inferiore a 1, inizierà sempre con uno 0 in atto per quelle cifre (come nei casi di test 5-8).
  • Il numero di input non sarà mai negativo
  • Gli built-in che rendono questa sfida banale e le scappatoie standard non sono consentite
  • Una nuova riga finale nell'output è OK

EDIT
Grazie a user81655 per aver segnalato i casi di test 7 e 8 avevano poteri errati di dieci. Ora li ho riparati, quindi assicurati che il tuo codice li valuti correttamente.


7
Quindi, dovrei chiedere quale pi^e^i^j^k^std::vectorsarebbe l'output per l'input ?
Geobits il

@Geobits Hmm, beh, se puoi assegnare un valore numerico a std :: vector, allora forse ... No, nell'input saranno presenti solo numeri (tranne una cifra decimale per l'input in virgola mobile).
MC ΔT

Questo sarebbe molto più semplice ee9000 -> 9e3
occuperemmo

1
@Cyoce Ci ho pensato, ma ho davvero basato questa sfida sul modo in cui è generalmente scritta (come in quella scritta fisicamente), che sembra stare con x10^. E sarebbe una buona dose di rielaborazione della domanda, che non credo sia così appropriata ora che è stata pubblicata
MC ΔT

1
@ghosts_in_the_code Non lo era, quindi "mi ha riportato alcuni anni a quando l'ho imparato per la prima volta [in classe di matematica]"
MC ΔT

Risposte:


4

ES6, 83 81 byte

x=>(e=s=>s.replace(/e\+?/,'x10^'),z=e(x.toExponential()),y=e(''+x))[z.length]?z:y

Probabilmente fallisce per alcuni casi limite in cui toStringinsiste sul formato esponenziale.

Modifica: salvato 2 byte grazie a @ user81655.


Bella idea A proposito, sembra che tu abbia dimenticato /la fine della regex.
user81655

Inoltre potresti riorganizzarlo leggermente per risparmiare 2 byte:x=>(e=s=>s.replace(/e\+?/,'x10^'),z=e(x.toExponential()),y=e(''+x))[z.length]?z:y
user81655

@ user81655 Ah, quello che è successo lì è che il mio browser mi ha confuso avvolgendo la linea lunga in modo tale che pensavo che una nuova linea si fosse insinuata lì per errore.
Neil,

2

Python 3, 346 342 319 302 byte

L=len;N=str(float(input()))
if N.endswith('.0'):N=N[:-2]
if'e'in N:C,P=N.split('e');N=N.replace('e','x10^')
else:
 C=N.strip('.0').replace('.','');F=N.find('.')
 if L(C)>1:C=C[0]+'.'+C[1:]
 P=((L(N) if F==-1 else F)-1-N.lstrip('0').find(C[0]))
print(min([N,'{0}x10^{1}'.format(C,int(P))],key=L))

Probabilmente orribilmente golf, ma ehi, questo è il mio primo tentativo in qualcosa del genere. È difficile da leggere, quindi deve essere buono.

Per quanto ne so, dovrebbe funzionare su tutti i casi, anche con la tendenza di Python a convertire automaticamente i numeri oltre qualsiasi soglia in notazione scientifica (tranne con quella "e" fantastica e fantasiosa). Non ricordo esattamente come l'ho reso in grado di restituire i numeri di modulo standard, ma lo fa.


2

Perl 6, 96 90 byte

Sento che questo potrebbe essere più breve, ma questo è il mio meglio per ora

{my \s=($_,*×(1>$_??10!!.1)…10>*>=1);min(s[*-1]~"x10^"~(1>$_??1-s!!s-1),$_,by=>&chars)}

utilizzo : assegnare questo a una variabile

Qui è un po 'ungolf con qualche brutto commento:

my &f = -> $n {
    my $a = 1 > $n ?? 10 !! .1;             # If $n < 1, we will multiply by 10
                                            # in the sequence below, else by 0.1

    my @seq = ($n, * × $a ... 10 > * >= 1); # Sequence starting at $n, 
                                            # multiply the previous value by $a
                                            # until we reach a number 1 <= x < 10

    # Join the last element in @seq, "x10^", and the length of @seq,
    # with an extra subtraction for numbers less than 1.
    # this gets us our scientific notation.
    my $science = @seq[*-1] ~ "x10^" ~ @seq - (1 > $n ?? @seq*2 !! 1); 

    min($science, $n, by => &chars) # Uses the &chars function to
                                    # choose a min value and return it.
}

Scambia $_ <1con 1>$_e 1 <=* <10con10>*>=1
Brad Gilbert b2gills il

In realtà intendevo farlo ieri sera, ma mi ero dimenticato. Lo aggiornerò quando torno a casa
Tasti di scelta rapida,

2

TI BASIC (nspire): 112 byte

Define f(x)=
Prgm
string(x)➝a
If x≥1 Then
format(x,"s")➝a
EndIf
instring(a,"ᴇ")➝b
left(a,b-1)&"x10^"&mid(a,b+1)➝a
If dim(a)<dim(string(n)) or x<1 Then
Disp a
Else
Disp x
Endif
EndPrgm

Spiegazione

If x≥1 Then
format(x,"s")➝a
EndIf

Converte l'input in notazione scientifica con la funzione di formattazione, se non è già in quel formato, poiché i piccoli decimali vengono convertiti automaticamente.

instring(a,"ᴇ")➝b
left(a,b-1)&"x10^"&mid(a,b+1)➝a

Trova la posizione della fantasia E che denota esponenti e la sostituisce con "x10 ^".

If dim(a)<dim(string(x)) or x<1 Then
Disp a
Else
Disp x
Endif

Verifica quale output è più grande e restituisce quello ottimale. A meno che non sia un piccolo decimale, che per impostazione predefinita sono più piccoli.


0

Python (3.5) 177 byte

Una soluzione che utilizza l'espressione regolare

import re
g=lambda s:re.sub(r"e\+?(-?)0?","x10^\\1",s)
def f(i):
 t=g(re.sub(r"\.[0]*e","e","%e"%i))
 u=g(re.sub(r"(\..*)[0]*$","\\1",str(i)))
 return t if len(u)>len(t) else u

Spiegazione

Importazione del modulo regexp

import re

Definizione della funzione lambda in sostituzione edix10^

g=lambda s:re.sub("e\+?(-?)0?","x10^\\1",s)
def f(i):

Conversione della stringa in notazione scientifica

 t=g(re.sub(r"\.[0]*e","e","%e"%i))

Rimuovi 0 padding nella stringa originale

 u=g(re.sub(r"(\..*)[0]*$","\\1",str(i)))

confrontare la lunghezza

 return t if len(u)>len(t) else u

risultati

>>> [f(i) for i in [1, 20, 3000000, 400000, 0.008093, 0.007835000000000, 0.000003000000, 0.00000065, 0]]
['1', '20', '3x10^6', '400000', '0.008093', '0.007835', '3x10^-6', '6.5x10^-7', '0']
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.