25
\$\begingroup\$

When writing programs, I usually end up using some numeric constants. I always put them in decimal because that's how I think, but I just realized that my language supports other number formats that might let me shorten my code slightly.

Challenge

Given a non-negative integer less than 2^53-1, decide whether that integer has the shortest representation in:

  • Decimal
  • Hexadecimal
  • Scientific Notation

Decimal

Since this is the default format of my language, there is no extra notation needed for this format. Every number is represented as usual for decimal.

Hexadecimal

My languages uses the 0x prefix for hexadecimal constants. This means that if a number has 4 hexadecimal digits, it will take 6 bytes to represent that number.

Scientific notation

My language uses the following format for scientific notation:

[Real base]e[Integer exponent of 10]

For example, 700 would be represented as 7e3, and 699 would be represented as 6.99e3, because the base must be between -10 and 10 (non-inclusive). For the purposes of this challenge, the base will always be at least 0, since the inputted number is non-negative.

Output

You should return a way of identifying which format is shortest (i.e. 0 for decimal, 1 for hex, 2 for scientific). Alternatively, you may output the smallest representation of the number itself.

Test cases

Decimal       | Hexadecimal  | Scientific        | Winner
--------------|--------------|-------------------|-------------
0             | 0x0          | 0e0               | Decimal
15            | 0xF          | 1.5e1             | Decimal
6999          | 0x1B57       | 6.999e3           | Decimal
7000          | 0x1B58       | 7e3               | Scientific
1000000000000 | 0xE8D4A51000 | 1e12              | Scientific
1000000000001 | 0xE8D4A51001 | 1.000000000001e12 | Hexadecimal
1000000001000 | 0xE8D4A513E8 | 1.000000001e12    | Hexadecimal
1000001000000 | 0xE8D4B45240 | 1.000001e12       | Scientific

Scoring

This is , so the answer in the shortest bytes for each language wins.

\$\endgroup\$
24
  • 1
    \$\begingroup\$ The requirement to go up to 2^63-1 may be difficult for some languages. Consider relaxing that to a lower value such as 2^32-1 (so the values fit in a double floating point data type) \$\endgroup\$
    – Luis Mendo
    Commented Jun 2, 2017 at 14:14
  • 1
    \$\begingroup\$ I see. How about 2^52-1? That still fits in double. Just a suggestion; do as you see fit \$\endgroup\$
    – Luis Mendo
    Commented Jun 2, 2017 at 14:16
  • 1
    \$\begingroup\$ 1000001000000 can also be written as 1000001e6 though. \$\endgroup\$ Commented Jun 2, 2017 at 14:33
  • 1
    \$\begingroup\$ @JonathanAllan yes, that was @ you, sorry. And no, you may not output the ordered list; since this is a decision-problem, you need to decide on one single output. (But your implementation may sort the list and output the first item.) \$\endgroup\$ Commented Jun 2, 2017 at 14:53
  • 1
    \$\begingroup\$ Isn't a decision-problem by definition only supposed to have two possible outputs? \$\endgroup\$
    – mbomb007
    Commented Jun 2, 2017 at 15:52

10 Answers 10

5
\$\begingroup\$

05AB1E, 23 bytes

hg̹gD<g>¹ÀðìÁ0ÜðÜg+)Wk

Try it online!

-1 thanks to Emigna.

0 for hexadecimal, 1 for decimal, 2 for scientific.

\$\endgroup\$
2
  • \$\begingroup\$ Save a byte with '.ìÁ0. \$\endgroup\$
    – Emigna
    Commented Jun 2, 2017 at 16:07
  • \$\begingroup\$ @Emigna ooh that prepend always golfs stuff. \$\endgroup\$ Commented Jun 2, 2017 at 16:08
4
\$\begingroup\$

05AB1E, 27 bytes

Dg<¹À'.ìÁ0Ü'.Ü…ÿeÿIh…0xÿ)é¬

Try it online!

Explanation

D                            # duplicate input, one copy will be used as decimal notation
 g<                          # len(input)-1
   ¹À                        # push input and rotate left
     '.ìÁ                    # prepend a dot and rotate right
         0Ü'.Ü               # remove trailing zeroes and then any trailing dot
              …ÿeÿ           # format scientific notation
                  Ih         # input converted to hex
                    …0xÿ     # format hex
                        )    # wrap in a list
                         é   # sort by length
                          ¬  # get the first (shortest) item
\$\endgroup\$
7
  • \$\begingroup\$ Ew, there should be something shorter here. \$\endgroup\$ Commented Jun 2, 2017 at 14:55
  • \$\begingroup\$ @EriktheOutgolfer: Probably. I spend a lot of bytes with the scientific notation. It would probably be shorter to not create the actual values and only check the lengths instead. \$\endgroup\$
    – Emigna
    Commented Jun 2, 2017 at 14:56
  • \$\begingroup\$ Hex length is len(hex(input)) + 2, if that helps. \$\endgroup\$ Commented Jun 2, 2017 at 14:58
  • \$\begingroup\$ @EriktheOutgolfer: Yeah, 5 bytes to get lengths of hex and decimal. It's the scientific notation that will cost bytes. Will likely beat this though. \$\endgroup\$
    – Emigna
    Commented Jun 2, 2017 at 14:59
  • 2
    \$\begingroup\$ @EriktheOutgolfer: Using ¹ instead of Ds: g¹hgÌ \$\endgroup\$
    – Emigna
    Commented Jun 2, 2017 at 15:08
3
\$\begingroup\$

Jelly, 28 bytes

TṀµỊ¬+‘
DµL’DL+Ç,L
b⁴L+2;ÇỤḢ

A monadic link returning 1, 2, or 3 for hexadecimal, scientific, or decimal respectively.

Try it online! or see a test suite.

I thought this would be shorter, but I can't see it so am posting.

How this monstrosity works...

TṀµỊ¬+‘    - Link 1, length of mantissa + "e": list of decimal digits  e.g. [7,0,1,0]
T          - truthy indexes                                                 [1,  3  ]
 Ṁ         - maximum                                                             3
  µ        - monadic chain separation, call that m
   Ị       - insignificant? (abs(m)<=1) -- here: 1 for m=1, 0 otherwise          0
    ¬      - logical not                  i.e. 1 if a "." will be used           1
     +     - add m                                                               4
      ‘    - increment                    always uses an 'e'                     5

DµL’DL+Ç,L - Link 2, lengths of scientific and decimal notations: non-negative-integer, n
D          - cast to decimal list
 µ         - monadic chain separation, call that d
  L        - length of d (number of decimal digits of n)
   ’       - decrement (value of exponent)
    D      - cast to decimal list (exponent's digits)
     L     - length (number of characters in the exponent)
       Ç   - call last link (1) as a monad(d) (number of characters in mantissa + "e")
         L - length of d (number of decimal digits of n)
        ,  - pair

b⁴L+2;ÇỤḢ - Main link: non-negative-integer, n
 ⁴        - literal 16
b         - convert n to base 16
  L       - length (number of hexadecimal digits)
   +2     - add two (number of characters including the "0x")
      Ç   - call the last link (2) as a monad (characters in scientific and decimal)
     ;    - concatenate ([charsInHexadecimal, charsInScientific, charsInDecimal])
       Ụ  - sort indexes by value
        Ḣ - head (1-based-index in the above list of (one of) the shortest)
\$\endgroup\$
6
  • 1
    \$\begingroup\$ 28 bytes!? Might as well use C#... :P \$\endgroup\$ Commented Jun 2, 2017 at 15:44
  • 1
    \$\begingroup\$ @TheLethalCoder Definitely a deceptive challenge - there must be a GL out there that can just format numbers to the scientific notation! \$\endgroup\$ Commented Jun 2, 2017 at 15:46
  • \$\begingroup\$ @TheLethalCoder There's a 75 byte Jelly answer posted on another question not that long ago. Can't remember what one. Ah it was this one, but this one is 83. \$\endgroup\$ Commented Jun 2, 2017 at 16:19
  • \$\begingroup\$ @Draco18s both mine I see! The comment made me look at this one which was standing at 91 from 8 months ago; I golfed it down to 85 :) \$\endgroup\$ Commented Jun 2, 2017 at 17:45
  • \$\begingroup\$ I had to le google the phrase "longest Jelly" restricted to codegolf.stackexchange.com in order to find them. :P There was a third, but it was only a paltry 57 bytes....Also yours. \$\endgroup\$ Commented Jun 2, 2017 at 17:53
2
\$\begingroup\$

JavaScript (ES6), 90 bytes

Returns 0 for decimal, 1 for hexadecimal, -1 for scientific.

n=>(l=Math.log,D=l(n)/l(10),H=l(n)/l(16)+2,S=n.toExponential().length-1,S<H?-(S<D):+(H<D))

f=
n=>(l=Math.log,D=l(n)/l(10),H=l(n)/l(16)+2,S=n.toExponential().length-1,S<H?-(S<D):+(H<D))

console.log(
    f(0),
    f(15),
    f(6999),
    f(7000),
    f(1000000000000),
    f(1000000000001),
    f(1000000001000),
    f(1000001000000)
)

Explanation

  • log(n) / log(10): base-10 logarithm of n; roughly the length of n as a decimal.

  • log(n) / log(16) + 2: base-16 logarithm of n plus 2; roughly the length of n as a hexadecimal plus the prepended 0x.

  • n.toExponential().length - 1: n.toExponential() returns a string with n in scientific format (e.g. 7e+3) but we subtract 1 from its length to account for the extraneous +.

Now that we have the lengths of all 3 representations D, H, andS, we compare:
S<H?-(S<D):+(H<D)


JavaScript (ES6), 97 bytes

This one outputs the number in the format with the shortest length. Inspired by @Shaggy's deleted attempt.

n=>[n+'','0x'+n.toString(16),n.toExponential().replace('+','')].sort((x,y)=>x.length-y.length)[0]

f=
n=>[n+'','0x'+n.toString(16),n.toExponential().replace('+','')].sort((x,y)=>x.length-y.length)[0]

console.log(
    f(0),
    f(15),
    f(6999),
    f(7000),
    f(1000000000000),
    f(1000000000001),
    f(1000000001000),
    f(1000001000000)
)

\$\endgroup\$
2
  • \$\begingroup\$ Nice :) I wonder could you pillage anything from my abandoned attempt at a solution to golf this down further? You'll find it in the deleted posts at the end of the page. \$\endgroup\$
    – Shaggy
    Commented Jun 2, 2017 at 19:27
  • \$\begingroup\$ @Shaggy Yours is fundamentally different since it outputs the formatted number. I added a separate answer based off of it instead. :) \$\endgroup\$
    – darrylyeo
    Commented Jun 2, 2017 at 20:42
1
\$\begingroup\$

C#, 106 97 96 143 132 bytes

using System.Linq;n=>new[]{n+"",$"0x{n:X}",(n+"").Insert(1,".").TrimEnd('0','.')+"e"+((n+"").Length-1)}.OrderBy(s=>s.Length).First()

Annoyingly in C# the ulong.ToString format specifier e loses precision on the higher numbers so I've had to do it manually. There's probably a shorter way to do it but this works for now. It also formats it incorrectly for this challenge so I would have to manually strip it's output anyway.

If I set a string to the value of n as var s=n+""; it works out longer because of the explicit return and extra curly braces.

It returns the shortest value from the array of each different value where [0] = decimal, [1] = hexadecimal, [2] = scientific.

Full/Formatted version:

using System.Linq;
Func<ulong, string> f = n =>
    new[]
    {
        n + "",
        $"0x{n:X}",
        (n + "").Insert(1, ".").TrimEnd('0', '.') + "e" + ((n + "").Length - 1)
    }.OrderBy(s => s.Length).First();

The correct way to calculate the scientific output is:

(n < 1 ? n + "" : (n + "").Insert(1, ".").TrimEnd('0', '.')) + "e" + ((n + "").Length - 1)

However, seeing as 0 is shorter than 0e0 I can remove that special case.

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

Python 2, 83 77 bytes

Outputs the smallest representation of the number.

import re
lambda n:min(`n`,hex(n),re.sub('\.?0*e\+0?','e','%.15e'%n),key=len)

Try it online

Ungolfed:

import re
n=input()
d=`n`
h=hex(n)
s=re.sub('(.)\.?0*e\+0?',r'\1e','%.15e'%n)
print min(d,h,s,key=len)

The regex removes trailing zeros and the decimal point if necessary, as well as the plus sign and leading zero from the exponent if there is one.

\$\endgroup\$
4
  • \$\begingroup\$ I think the backticks will append an L to large numbers within the input range. str would avoid that. \$\endgroup\$
    – xnor
    Commented Jun 2, 2017 at 16:15
  • \$\begingroup\$ @xnor The maximum integer we have to support is within Python's int representation. Longs start at roughly 2**63. \$\endgroup\$
    – mbomb007
    Commented Jun 2, 2017 at 16:16
  • \$\begingroup\$ Do you need to do the regex subbing? Can you just remove + characters with str.replace? \$\endgroup\$ Commented Jun 2, 2017 at 17:47
  • 1
    \$\begingroup\$ @musicman523 That'd be a lot longer. The regex subbing needs to be done anyway for removing the zeros and decimal point, and it's only 2 bytes to remove the + while I'm at it. \$\endgroup\$
    – mbomb007
    Commented Jun 2, 2017 at 18:31
1
\$\begingroup\$

Ohm, 35 bytes

l┼xl2+┼DRîsRl≥al≤Dla°┼îa/ì\?≥;+WD╤k

Try it online!

Outputs 0 for decimal, 1 for hex and 2 for scientific.

Explanation:

l                                      Implicit input, get length                                          
 ┼                                     Input again
  x                                    To hex
   l                                   Get length
    2+                                 Add 2 because of "0x"
      ┼                                Get input again
       D                               Duplicate on the stack
        RîsR                           Remove zeroes at the end (reverse, to int, to string, reverse)
            l                          Get length (= length of base)
             ≥                         Add 1 because to count "e" in the scientific notation
              a                        Swap top two values on the stack
               l≤                      Get length - 1 ( = get the exponent of 10 in scientific notation)
                 D                     Duplicate on the stack
                  l                    Get length ( = length of the exponent)
                   a                   Swap. Now on top of the stack we have the exponent again
                    °                  10^exponent
                     Ō                Get input for the fourth time
                       a/              Divide input by the 10^exp calculated earlier
                         ì\?           If this thing is not an integer...
                            ≥;         ...add one to count the "."
                              +        Sum base length ( + "e") + exponent length ( + ".")
                               W       Wrap stack in array
                                D      Duplicate
                                 ╤k    Get index of min value
\$\endgroup\$
0
\$\begingroup\$

PHP, 90 bytes

prints 0 for decimal, 1 for hexadecimal and 2 for scientific

in case of a tie the highest number will be print

<?=array_flip($m=[$l=log10($a=$argn)^0,2+(log($a,16)^0),strlen(($a/10**$l).$l)])[min($m)];

Try it online!

PHP, 91 bytes

prints 0 for decimal, 1 for hexadecimal and 2 for scientific

in case of a tie the lowest number will be print

<?=array_search(min($m=[$l=log10($a=$argn)^0,2+(log($a,16)^0),strlen(($a/10**$l).$l)]),$m);

Try it online!

PHP, 103 bytes

prints 0 for decimal, 1 for hexadecimal and 2 for scientific

in case of a tie all numbers will be print

foreach($m=[$l=log10($a=$argn)^0,2+(log($a,16)^0),strlen(($a/10**$l).$l)]as$k=>$v)echo$v-min($m)?"":$k;

Try it online!

PHP, 109 bytes

Output an array with the shortest solutions

for(;!$p=preg_grep("#^.{".++$i."}$#",[$a=$argn,"0x".dechex($a),$a/10**($l=log10($a)^0)."e$l"]););print_r($p);

Try it online!

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

C, 187185 bytes

main(){long long N;scanf("%lli",&N);long long D=log10(N)+1,H=log(N)/log(16)+3,F,S,i=1;while(N>i&&!(N%i))i*=10,F++;S=ceil(log10(D-1))+1+D-F+(D-F>1);printf("%i",N?H>D?2*(D>S):1+(H>S):N);}

Decompressed:

void main(){
    long long N;
    scans("%lli", &N);
    long long D = log10(N) + 1; // Length of number (decimal)
    long long H = log(N)/log(16) + 3; // Length of number (hexadecimal)
    long long F; // Number of 0s at the end of decimal number
    long long S; // Length of number (scientific notation)
    long long i; // Counter (more or less)
    // Get number of zeros at the end of decimal number
    while(N > i && (N % i) == 0){
        i = i * 10;
        F++;
    }
    S = ceil(log10(D - 1)) + 1 + D - F + (D-F>1); // (Power) + (e) + (multiplier + (1 if len(multiplier) > 1))
    printf("%i", N!=0 ?
                (H > D ? 2 * (D > S) : 1 + (H > S)) 
              : 0); // Print the shortest number
}

Prints 0 for decimal, 1 for hex, 2 for scientific notation.

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

TI-Basic, 130 bytes

Input N:If not(N:Goto 0:1+int(log(N→D:3+int(logBASE(N,16→H:0→F:1→I:While N>I and not(fPart(N/I:10I→I:F+1→F:End:log(D-1→L:1+D-F+(D-F>1):Ans+int(L)+(0≠fPart(L→S:(H>D)2(D>S)+(H≤D)(1+(H>S)→N:Lbl 0:N

Or, alternatively:

�N>θN>�0>1p��ND>3p�������BASEN+16H>0F>1I>�NlI@��N�I>10II>Fp1F>�>�Dq1L>1pDqFpDqFl1>rp�Lp0o�LS>HlD2DlSpHmD1pHlSN>�0>N

Or, in hex:

dc4e3eceb84e3ed7303e3170b1c04e04443e3370b1bbbcbbbfbbb642415345104e2b313604483e3004463e3104493ed14e6c4940b8ba4e83493e31304904493e46703104463ed43ec0447131044c3e317044714670104471466c31113e7270b14c117010306fba4c04533e10486c44113210446c53117010486d441110317010486c5311044e3ed6303e4e

Prints 0 for decimal, 1 for hex, 2 for scientific notation

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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