Help me golf my numbers!

25

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.

musicman523

Posted 2017-06-02T14:11:25.177

Reputation: 4 472

Relevant – musicman523 – 2017-06-02T14:12:39.360

1The 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) – Luis Mendo – 2017-06-02T14:14:33.133

To clarify: we can either output all 3 reprsentations of the number or the name of the single representation that uses the least amount of characters? – Shaggy – 2017-06-02T14:15:07.503

@LuisMendo Unfortunately hex never wins below 2^32, which is why I made this requirement – musicman523 – 2017-06-02T14:15:46.477

1I see. How about 2^52-1? That still fits in double. Just a suggestion; do as you see fit – Luis Mendo – 2017-06-02T14:16:51.330

@Shaggy you should either:

  1. Decide upon three unique results for the winning format, such as 0 for decimal, 1 for hex, and 2 for scientific, and always output those (see this meta question, but instead of Truthy/Falsey, you should choose 3 distinct outputs), or
  2. Output the best representation of the integer
– musicman523 – 2017-06-02T14:17:32.217

@LuisMendo Updated. My original intent was for C/C++/Java users to use long (and Scala to use Long), but if it's easier to use doubles then go for it – musicman523 – 2017-06-02T14:21:57.543

Gotcha! Thanks for clearing that up. Can we take input as a string? – Shaggy – 2017-06-02T14:22:23.823

I think the limit for double is 2^53-1, so you could still increase by a factor of 2 – Luis Mendo – 2017-06-02T14:29:15.410

@Shaggy I'm not sure, I can't find a consensus on that issue. If you can find one in the codegolf meta, could you link it here? Otherwise for now, just leave a footnote on your answer showing how it can be shortened with the alternative input format – musicman523 – 2017-06-02T14:29:59.423

@LuisMendo Thanks, updated – musicman523 – 2017-06-02T14:30:05.987

11000001000000 can also be written as 1000001e6 though. – Erik the Outgolfer – 2017-06-02T14:33:48.613

@EriktheOutgolfer AFAIK most languages don't use scientific notation like that – Stephen – 2017-06-02T14:38:36.690

@EriktheOutgolfer Sorry, I should have specified more clearly - this challenge uses the standard form for scientific notation

– musicman523 – 2017-06-02T14:41:34.750

@StephenS Output from repr-like functions won't be like that but you can perfectly write that as a literal. – Erik the Outgolfer – 2017-06-02T14:45:07.070

@musicman523 ooh that's actually quite challenging – Erik the Outgolfer – 2017-06-02T14:45:22.533

If two notations tie (e.g. hex & dec for 10000000001) may we output just one? May we output both? – Jonathan Allan – 2017-06-02T14:45:59.183

You may do either – musicman523 – 2017-06-02T14:46:24.617

...and may we output a list of identifiers in order? – Jonathan Allan – 2017-06-02T14:48:25.790

1@JonathanAllan yes, that was @ you, sorry. And no, you may not output the ordered list; since this is a [tag:decision-problem], you need to decide on one single output. (But your implementation may sort the list and output the first item.) – musicman523 – 2017-06-02T14:53:29.503

Annoyingly in C# ulong.ToString("e"), converting to scientific notation, loses precision on the larger numbers. So I'm going to have to do that conversion manually. – TheLethalCoder – 2017-06-02T15:11:16.183

1Isn't a [tag:decision-problem] by definition only supposed to have two possible outputs? – mbomb007 – 2017-06-02T15:52:04.107

It looks like, according to this meta post, it should be a [tag:classification] problem. I'll make this change.

– musicman523 – 2017-06-02T17:35:33.540

I'm sandboxing Part 2 now, if anyone would like to help!

– musicman523 – 2017-06-02T20:29:32.727

Answers

5

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.

Erik the Outgolfer

Posted 2017-06-02T14:11:25.177

Reputation: 38 134

Save a byte with '.ìÁ0. – Emigna – 2017-06-02T16:07:06.650

@Emigna ooh that prepend always golfs stuff. – Erik the Outgolfer – 2017-06-02T16:08:24.510

4

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

Emigna

Posted 2017-06-02T14:11:25.177

Reputation: 50 798

Ew, there should be something shorter here. – Erik the Outgolfer – 2017-06-02T14:55:29.300

@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. – Emigna – 2017-06-02T14:56:26.877

Hex length is len(hex(input)) + 2, if that helps. – Erik the Outgolfer – 2017-06-02T14:58:04.023

@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. – Emigna – 2017-06-02T14:59:55.390

Sure? It seems like 6 to me (DhgÌsg). – Erik the Outgolfer – 2017-06-02T15:03:44.673

2@EriktheOutgolfer: Using ¹ instead of Ds: g¹hgÌ – Emigna – 2017-06-02T15:08:37.907

Let us continue this discussion in chat.

– Erik the Outgolfer – 2017-06-02T16:01:03.143

3

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)

Jonathan Allan

Posted 2017-06-02T14:11:25.177

Reputation: 67 804

128 bytes!? Might as well use C#... :P – TheLethalCoder – 2017-06-02T15:44:46.350

1@TheLethalCoder Definitely a deceptive challenge - there must be a GL out there that can just format numbers to the scientific notation! – Jonathan Allan – 2017-06-02T15:46:50.647

@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.

– Draco18s no longer trusts SE – 2017-06-02T16:19:44.053

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

– Jonathan Allan – 2017-06-02T17:45:38.890

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.

– Draco18s no longer trusts SE – 2017-06-02T17:53:13.193

Ah well then there is code-bowling 15,410 cracking Dennis's 25,394.

– Jonathan Allan – 2017-06-02T17:58:27.063

2

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

darrylyeo

Posted 2017-06-02T14:11:25.177

Reputation: 6 214

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. – Shaggy – 2017-06-02T19:27:06.843

@Shaggy Yours is fundamentally different since it outputs the formatted number. I added a separate answer based off of it instead. :) – darrylyeo – 2017-06-02T20:42:52.177

1

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.

TheLethalCoder

Posted 2017-06-02T14:11:25.177

Reputation: 6 930

1

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.

mbomb007

Posted 2017-06-02T14:11:25.177

Reputation: 21 944

I think the backticks will append an L to large numbers within the input range. str would avoid that. – xnor – 2017-06-02T16:15:13.363

@xnor The maximum integer we have to support is within Python's int representation. Longs start at roughly 2**63. – mbomb007 – 2017-06-02T16:16:46.787

Do you need to do the regex subbing? Can you just remove + characters with str.replace? – musicman523 – 2017-06-02T17:47:50.527

1@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. – mbomb007 – 2017-06-02T18:31:24.380

1

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

FrodCube

Posted 2017-06-02T14:11:25.177

Reputation: 539

0

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.

Élektra

Posted 2017-06-02T14:11:25.177

Reputation: 284

0

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!

Jörg Hülsermann

Posted 2017-06-02T14:11:25.177

Reputation: 13 026

0

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

Élektra

Posted 2017-06-02T14:11:25.177

Reputation: 284