12
\$\begingroup\$

The other day my chemistry teacher was explaining to us about scientific notation (using a small number and multiplying it by powers of ten to express large numbers more easily), which brought me back a few years to when I first learnt it. After learning the basics, we had done a bunch of typical maths questions, some of which were like the following:

Represent the following in scientific notation:
a) 50000000
b) 120000000000000
c) 90000000000000000000000000000000000000
d) pi^e^i^j^k^std::vector
...
z) 200
...

And I thought, "What? We were told that scientific notation was used to make writing large numbers more efficient, but some cases aren't more efficient at all!"

Consider the number

300

and its representation in scientific notation:

3x10^2

What, the scientifically notated version actually takes up more space? We can't have that now can we? (Screen space is precious.)
We could determine ourselves if it's more space efficient to write a number in scientific notation or not, or...

Task

Your program or function should take as input a single positive number n of arbitrary size (up to what your language supports) and output the scientifically notated version of the number.
However, if the original number n, after removal of trailing zeroes and trailing decimal place, takes less or the same amount of characters to display than its scientifically notated version, you must output that original number n instead.

Your code needs to be as short as possible because the output also has to be as short as possible.

Specifications

Efficient Scientific Notation is defined as follows:

bx10^e

b is the input number appropriately divided by powers of 10 such that 1 <= b < 10. This number must have all trailing zeroes (and decimal point if required) removed, but must have the precision of the original number (up to the decimal point limit in your language, of course). Ie 90000 becomes 9, 13.500 becomes 1.35, 0.000675 becomes 6.75 etc. If this number ends up containing more decimal places than your language can handle, it should be rounded to that maximum number of decimal places.

e is the exponent to which ten is raised such that n = b x 10^e (remember that this number needs to be negative if n is smaller than 1). This number should not have any trailing zeros or a decimal place (mainly because if it's not an integer something is wrong...).

The characters x10^ must remain as is in the string between b and e.

Test cases

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

Scoring

This is , so shortest code in bytes wins.

Other rules and clarification

  • Trailing zeros (and/or trailing decimal place) are not counted towards the character count of the original input number n. Keep that in mind for cases such as test case 6
  • You may assume that if the input number is less than 1, it will always start with a 0 in place for the ones digit (as in test cases 5-8).
  • Input number will never be negative
  • Built-ins that make this challenge trivial and standard loopholes are disallowed
  • A trailing newline in the output is OK

EDIT
Thanks to user81655 for pointing out test cases 7 and 8 had incorrect powers of ten. I have now fixed those so make sure your code evaluates them correctly.

\$\endgroup\$
  • 7
    \$\begingroup\$ So, uh, should I ask what the output for input pi^e^i^j^k^std::vector would be? \$\endgroup\$ – Geobits Feb 6 '16 at 7:03
  • \$\begingroup\$ @Geobits Hmm, well if you can assign a numerical value to std::vector then maybe... No, only numbers will be present in the input (except a decimal place for floating point input). \$\endgroup\$ – MC ΔT Feb 6 '16 at 7:20
  • \$\begingroup\$ This would be far easier and we would take up less of your "precious screen space" if it used e: 9000 -> 9e3 (almost over 9,000!) \$\endgroup\$ – Cyoce Feb 6 '16 at 7:33
  • 1
    \$\begingroup\$ @Cyoce I thought about that, but I really based this challenge on the way it is generally written (as in physically written), which seems to be with x10^. And it would be a fair bit of rework on the question, which I don't think is that appropriate now that it's posted \$\endgroup\$ – MC ΔT Feb 6 '16 at 7:46
  • 1
    \$\begingroup\$ @ghosts_in_the_code She wasn't, hence "brought me back a few years to when I first learnt it [in maths class]" \$\endgroup\$ – MC ΔT Feb 7 '16 at 10:29
4
\$\begingroup\$

ES6, 83 81 bytes

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

Probably fails for some edge cases where toString insists on exponential format.

Edit: Saved 2 bytes thanks to @user81655.

\$\endgroup\$
  • \$\begingroup\$ Nice idea. By the way, it looks like you forgot the / at the end of the regex. \$\endgroup\$ – user81655 Feb 6 '16 at 11:41
  • \$\begingroup\$ Also you could rearrange this slightly to save 2 bytes: x=>(e=s=>s.replace(/e\+?/,'x10^'),z=e(x.toExponential()),y=e(''+x))[z.length]?z:y \$\endgroup\$ – user81655 Feb 6 '16 at 11:58
  • \$\begingroup\$ @user81655 Ah, what happened there is that my browser confused me by wrapping the long line in such a way as I thought that a new line had crept in there by mistake. \$\endgroup\$ – Neil Feb 6 '16 at 14:10
2
\$\begingroup\$

Python 3, 346 342 319 302 bytes

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

Probably horribly golfed, but hey, this is my first try at something like this. It's hard to read, so it must be good.

As far as I'm aware, it should work on every case, even with Python's tendency to automatically convert numbers past whatever threshold into scientific notation (except with that cool and fancy 'e'). I don't remember exactly how I made that be able to return standard form numbers, but it does that.

\$\endgroup\$
2
\$\begingroup\$

Perl 6, 96 90 bytes

I feel like this could be shorter, but this is my best for now

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

usage: Assign this to a variable

Here it is ungolfed a bit with some bad commentary:

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.
}
\$\endgroup\$
  • \$\begingroup\$ Swap $_ <1 with 1>$_ and 1 <=* <10 with 10>*>=1 \$\endgroup\$ – Brad Gilbert b2gills Feb 12 '16 at 18:38
  • \$\begingroup\$ I actually meant to do that last night but I forgot. I'll update it when I get home \$\endgroup\$ – Hotkeys Feb 12 '16 at 18:45
2
\$\begingroup\$

TI BASIC (nspire): 112 bytes

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

Explanation

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

Converts the input to scientific notation with the format function if it already isn't in that format- as small decimals are automatically converted.

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

Finds the position of the fancy E that denotates exponents and replaces it with "x10^".

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

Checks which output is larger and returns the optimal one. Unless it is a small decimal, which are smaller by default.

\$\endgroup\$
0
\$\begingroup\$

Python (3.5) 177 bytes

A solution using regular expression

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

Explanation

Importation of regexp module

import re

Définition of the lambda function to replace e by x10^

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

Convertion of the string in scientific notation

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

Remove 0 padding in the orginal string

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

compare length

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

Results

>>> [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']
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.