Expand the number

58

7

You may remember in first or second grade using expanded form to learn about place value of numbers. It's easier to explain with an example, so consider the number 123. In expanded form it is represented as 100 + 20 + 3, which helps a young mind visualize place value. It is reminiscent of how you say it: one hundred (plus) twenty (plus) three.

We can extend this past the units place with decimals: 2.718 => 2 + 0.7 + 0.01 + 0.008

Your challenge is to write a program or function that takes a positive floating point number or zero (assume it is as large or precise as your language can handle; it will not be in scientific notation) or string and prints/returns it in expanded form as explained above.

You need neither spaces between the +'s nor the zero before the decimal point, so the example above could be 2+.7+.01+.008. Values that would be equal to zero must be omitted (101.01 => 100 + 1 + 0.01) unless the input is zero (see below).

Values should not have more than one leading zero before the decimal point or any trailing zeroes after it (no-no's: 0060, 0000.2, 30., 30.000, .0400). The input will conform to this too.

Since first-graders have short attention spans, your code will have to be as short as possible.

Test cases

0 => 0
6 => 6
0.99 => 0.9 + 0.09
24601 => 20000 + 4000 + 600 + 1
6.283 => 6 + 0.2 + 0.08 + 0.003
9000000.0000009 => 9000000 + 0.0000009

NinjaBearMonkey

Posted 2016-01-09T01:35:12.643

Reputation: 9 925

22+1 for "Since first-graders have short attention spans, your code will have to be as short as possible." – Downgoat – 2016-01-09T01:42:00.363

Can the input be string? – Akangka – 2016-01-09T02:09:45.280

@ChristianIrwan Yes, it says so above, but I guess it's confusingly worded – NinjaBearMonkey – 2016-01-09T02:13:06.247

2

@Doᴡɴɢᴏᴀᴛ glad to see the meme is still running.

– cat – 2016-01-09T04:52:19.913

4It would have be funny to do it in the same way we (french) count, to see people strugle with the case of 97(4*20+10+7) ^^ – Katenkyo – 2016-01-18T12:14:19.090

CJam outputs 0.000009 as 0.000009 but 0.0000009 as 9e-7, and arguably it's too precise for CJam. Is that allowed? – jimmy23013 – 2016-01-18T13:34:41.293

2@jimmy23013 Yes, as long as it works in theory. – NinjaBearMonkey – 2016-01-18T14:07:13.910

Could the input have trailing zeros? E.g. 15.20 or 1.0. – randomra – 2016-01-18T22:15:22.557

@randomra No, the input will conform to the same restrictions as the output. – NinjaBearMonkey – 2016-01-18T22:18:24.927

@Katenkyo That would be horrible/hilarious! Perhaps it could be the seed of another puzzle? – Ogaday – 2016-01-21T10:08:08.737

@NBZ How does that give 197? – Thrax – 2016-01-21T13:07:29.497

1@Ogaday I don't know, it's only some edge cases. Maybe NBZ way would be better, but still, don't if it would really be interesting – Katenkyo – 2016-01-22T13:12:29.790

@Thrax Edit typo: Much worse in Danish: 197 = 100 + 7 + ((5 + 4) / 2) × 20.

– Adám – 2016-01-22T16:07:40.970

Answers

6

CJam, 33 26 bytes

r_ee\'0fe<f{\~t~}{},'+*0e|

This won't work with the Java interpreter; it print floats differently. Try it with the CJam interpreter.

The last test case prints 9000000+9e-7, which has been ruled valid by @NinjaBearMonkey.

Thanks to @jimmy23013 for golfing off 7 bytes!

How it works

r_                           Read a token from STDIN and push a copy.
  ee                         Enumerate its characters, i.e., push the array of all
                             [index character] pairs.
    \                        Swap the original input on top of the stack.
     '0fe<                   Perform vectorized minimum with the character '0'.
                             This replaces all digits with '0', but leaves '.'
                             untouched, since `.' < '0'.
          f{    }            For each [index character] pair, push the pair and the
                             string of zeroes and (possibly) a dot; then:
            \                    Swap the pair on top of the stack.
             ~                   Dump index and character on the stack.
              t                  Replace the string's element at that index with
                                 that character.
               ~                 Evaluate the resulting string.
                 {},         Filter the array to remove zeroes.
                    '+*      Join, using '+' as separator.
                       0e|   If the result is empty, replace it with 0.

Dennis

Posted 2016-01-09T01:35:12.643

Reputation: 196 637

Based on the same idea: r_ee\'0fe<f{\~t~}{},'+*0e|. – jimmy23013 – 2016-01-21T19:41:37.493

@jimmy23013 Wow, that is short! Thank you! – Dennis – 2016-01-21T20:11:15.517

5

JavaScript (ES7), 102 bytes

n=>+n&&[...n.replace(/^\.0*|\./,"")].map(f=d=>10**p--*d,p=Math.floor(Math.log10(n))).filter(f).join`+`

Explanation

Requires the number to be input as a string without leading zeroes (unless the number is 0 of course).

Note: Because of floating-point weirdness some numbers (like .3) come out wrong, but theoretically this works for any number.

n=>                             // n = input number as string
  +n&&                          // return 0 if n = 0
  [...n.replace(/^\.0*|\./,"")] // remove leading zeroes after the decimal place
  .map(f=d=>                    // for each digit d in n
      10**p--*d,                // raise the digit to the correct power of 10
    p=Math.floor(Math.log10(n)) // p = power of 10 for the first digit, floor needs to be
  )                             //     used instead of |0 due to negative powers of 10 :(
  .filter(f)                    // remove zeroes, the map function is reused
  .join`+`                      // return the output numbers joined with +

Test

Test uses Math.pow instead of ** for browser compatibility.

var solution = n=>+n&&[...n.replace(/^\.0*|\./,"")].map(f=d=>Math.pow(10,p--)*d,p=Math.floor(Math.log10(n))).filter(f).join`+`
<input type="number" oninput="result.textContent=solution(this.value)">
<pre id="result"></pre>

user81655

Posted 2016-01-09T01:35:12.643

Reputation: 10 181

Math.floor => 0|...? – ETHproductions – 2016-01-10T22:54:24.453

@ETHproductions If the input number is less than 1 it would break because Math.log10(n) would return a negative number and |0 rounds towards zero instead of flooring. – user81655 – 2016-01-10T23:22:43.137

Can you use 0|Math.log10(n),p-=p<0 instead of Math.floor(Math.log10(n))? – Dom Hastings – 2016-01-19T09:57:19.603

1@DomHastings Almost. It fails for n<1 because the 0| will make p equal 0 for both 0.1 and -0.1. The shortest way I can think of is p=Math.log10(n),p=p-(p<0)|0 which is the same length as using Math.floor. :( – user81655 – 2016-01-19T22:32:04.573

@DomHastings Still wouldn't work for n=0.1 anyway. – Neil – 2016-01-20T20:50:35.027

Test doesn't work for following: .3 -> 0.30000000000000004, .6 -> 0.6000000000000001, .7 -> 0.7000000000000001, and more importantly: 0.1 -> 0.01, 0.01 -> 0.0001, etc. All zeroes get doubled. So pretty much solution is broken. Solution is not about "someone's fault", but about "it works". DNQ. – metalim – 2016-10-28T07:26:06.593

@metalim In regards to your first tests, floating-point numbers cannot represent every real number. That's just how they work. The question asks for a floating-point number, so I'd assume your first examples are allowed. For the others, as I state in the description: *"Requires the number to be input as a string without leading zeroes"*. This is explicitly allowed by the question with *"You need neither spaces between the +'s nor the zero before the decimal point"* and the OP's comment "the input will conform to the same restrictions as the output". – user81655 – 2016-10-30T23:18:43.637

@user81655 Comment "the input will conform to" refers to invalid inputs - there are no 006 or 0.100 inputs allowed. Program should work for all valid inputs. As for floating point number representation: text representation is strict and easy: 0.3 does not equal 0.300000whatever. Task of a developer is to make a program that conforms to the requirements, not to explain the quirks of implementation instead. – metalim – 2016-11-04T15:28:16.123

5

Retina, 86 77 75 bytes

Byte count assumes that the source is encoded as ISO 8859-1.

S_`.(?<=(\.\d+))|(?=(\d*)).
Tm`d`0`\..+\B|(?<=^\d).+
¶([.0]+¶)*
+
^0.|\+0$

The trailing linefeed is significant.

Try it online.

Explanation

S_`.(?<=(\.\d+))|(?=(\d*)).

We start by turning the input into a linefeed separate list of components, although only the leading (or trailing) digit is correct. This is done by abusing a split stage. Instead of splitting the input we match all of it, so the remaining segments are all empty. We remove those empty segments with the _ option. The catch is that split stages also return the values of all capturing groups. So we use a lookahead at each match to capture the correct part of the string: first we try to find a . left of the match. If that's the case, we capture everything from the . up to and including the digit we're currently matching. Otherwise, we must be in the integer part of the input, so we capture all the numbers after the match (including the match). We must also get rid of the decimal point itself, so the second capture is optional. If there are no \d to be capture, this will simply remove the match from the input.

Tm`d`0`\..+\B|(?<!=\d).+

Now we use a transliteration stage to turn all but the leading/trailing digits into zeroes. We either match a component that's less than 1 with \..+\B where the \B ensures that we stop the match one digit before the end, or we match an integer part with (?<=^\d).+ where the lookbehind ensures that we start one digit into the number. The transliteration stage will then replace any digits (d) with zeroes inside the matches.

¶([.0]+¶)*
+

Now the actual output format should use + not linefeeds as separators. The matches a linefeed to do that substitution. While we're at it, we also remove lines that contain only 0s and .s.

^0.|\+0$

The previous stage does not remove a leading or trailing 0 (because those do not have a linefeed before and after them), so we remove those explicitly.

Martin Ender

Posted 2016-01-09T01:35:12.643

Reputation: 184 808

4

Python 2, 216 210 196 175 bytes

Here is some slightly golfed code that I will golf further when I get time. It uses string analysis.

i=input().split(".")
I=i[0]
e=enumerate
o=[(k+len(I[j+1::])*"0") for j,k in e(I) if k!="0"] 
try:o+=["."+l*"0"+m for l,m in e(i[1]) if m!="0"]
except:0
print "+".join(o or"0")

Explanation

So, the input is seperated into a integer and decimal part. Then, there is a for loop list comprehension. On the integer part, the length of the string after a character in the decimal is multiplied by "0" to get that many zeros at the end if that character.

For the decimal part, the index of the current character is the number of zeros before it and so that part is simple.

The try and except is used to determine whether it has a decimal part or not (using an error).

The final result is joined with plus signs.

Try it here!

TanMath

Posted 2016-01-09T01:35:12.643

Reputation: 1 431

2I think o if o else ["0"] can be o or["0"]. – lirtosiast – 2016-01-19T03:06:05.733

You have a trailing space on line four which adds to your byte count. On line four you only need one colon. You can delete the spaces in the following snippets: o=[(...)] for,e(I) if,e(i[1]) if,print "+", and the outer parenthesis in o=[(...) as well, actually. Finally, you can take the final conditional out of the join function like this: print"+".join(o)or"0" because join will return an empty list if o is empty so the conditional will evaluate the same way which saves you one byte. – Ogaday – 2016-01-21T10:26:20.163

3

Pyth, 30 bytes

L.xvbytb|j\+fT.eyXXzjkUT\0kbzz

Test suite

The basic solution here is to replace all of the digits in the input with 0, then insert each digit at the proper location, eval, filter out the zeros, and join on pluses. Unfortunately, Pyth's eval function doesn't accept leading zeros currently. I will be working to fix this.

To get past this problem, I added a helper function, y, which recursively retries the eval until no error is thrown, removing the first digit every time. Note that this function will loop infinitely on invalid input.

Also, a special case was needed for the input 0.

All in all, I think the code's pretty good, but the language facilities could be better. Who wants errors?

isaacg

Posted 2016-01-09T01:35:12.643

Reputation: 39 268

3

Python 3, 138

This is loosely based on TanMath/Ogaday's approach of reading the number as a string and parsing it out that way. I have to use star assignment on i so that it correctly handles integers.

j,*i=input().split(".")
e=enumerate
z="0"
print("+".join([(x+len(j[y+1:])*z)for y,x in e(j)if x>z]+["."+o*z+p for o,p in e(i)if p>z]or z))

Morgan Thrapp

Posted 2016-01-09T01:35:12.643

Reputation: 3 574

3

Python, 141 132 128 bytes

This one is still relatively readable. Convert to string and handle the >1 digits separately from the <1 digits. We also have a special case for zero. I could remove two more spaces below, but I like keeping it pretty.

The downside is that it will breakdown for floats with more than 9 decimal places.

x=str(int(a*1e9))
l=len(x)-10
z="0"
print"+".join([(j+z*(l-i))if l>=i
 else"."+z*(i-l-1)+j
 for i,j in enumerate(x)if j!=z]or z)

Below is the original. First edit was to shorten the zero special case, second edit was to remove the 0 before the decimal, third was to remove some extra parenthesis and spaces.

x=str(int(a*1e9))
l=len(x)-10
z="0"
print "+".join([(j+z*(l-i)) if l>=i
 else ("0."+z*(i-l-1)+j)
 for i,j in enumerate(x) if j!=z]) if a else z

Explanation:

x=str(int(a*1e9)) # Convert into a string with nine decimals
l=len(x)-10
z="0"
print "+".join([
 (j+z*(l-i)) if l>=i       # Print numbers greater than 1
 else ("0."+z*(i-l-1)+j)   # Print less than one
 for i,j in enumerate(x) if j!=z
]) if a else z             # Special case zero

speedplane

Posted 2016-01-09T01:35:12.643

Reputation: 131

You don't need to include every revision of your code; if we want to see your golfing progress we can look at the revision history. By the way, welcome to PPCG! – lirtosiast – 2016-01-25T20:32:05.160

1Just discovered it... I'm going to have to try not to spend too much time on this site! – speedplane – 2016-01-25T22:11:41.360

2

Mathematica, 81 bytes

Inactive@Plus@@(10.^Range[#2-1,#2-Length@#,-1]#/.{0.->Nothing[]})&@@RealDigits@#&

Test case:

%[101.01]
(* 100. + 1. + 0.01 *)

njpipeorgan

Posted 2016-01-09T01:35:12.643

Reputation: 2 992

3I don't think having the decimal point over the integer parts is allowed. – Martin Ender – 2016-01-18T11:33:24.467

2

CJam, 44 bytes

r:TdLT'.-{'0f+IaaI~g*+}fI:dATW%'.##m]f/'+*e&

Try it here.

It fails the last test case, and outputs the following:

9000000+9e-7

But let's say it's too precise that CJam cannot handle it.

Explanation

r:Td
LT'.-         e# Remove the period if any.
{             e# For each character I:
  '0f+        e# Append 0 to each previous string.
  IaaI~g*+    e# Append I as a string if I isn't '0.
}fI
:d            e# Convert each string to float.
ATW%'.##      e# 10 to the kth power where k is the position of the period from the end.
m]            e# Round up, so it becomes 1 if no periods are found.
f/            e# Divide each float by this number.
'+*e&         e# Format and the 0 special case.

jimmy23013

Posted 2016-01-09T01:35:12.643

Reputation: 34 042

2

Python 3, 187 180 173 154 bytes

Managed to golf a good 19 bytes off thanks to @Thomas Kwa's suggestions above about result or['0'], plus rearranging some algebra (154 bytes):

def f(n):
 *m,=n;o='0'
 try:p=m.index('.');m.pop(p)
 except:p=len(m)
 return'+'.join([['.'+o*(i-p)+d,d+o*(p-i-1)][p>i]for i,d in enumerate(m)if d!=o])or o

My best attempt so far (173 bytes). Based upon new approach, see bottom of post:

def f(n):
 *m,=n;o='0'
 try:p=m.index('.');m.pop(p)
 except:p=len(m)
 return(o,'+'.join([['.'+o*(-1*(p-i))+d,d+o*(p-i-1)][p-i>0]for i,d in enumerate(m)if d!=o]))[eval(n)!=0]

golfed my original down to 180 bytes:

def f(n):x=n.split('.');a,b=(x+[''],x)[len(x)-1];e=enumerate;return('0',"+".join([d+'0'*i for i,d in e(a[::-1])if d!='0'][::-1]+['.'+'0'*i+d for i,d in e(b)if d!='0']))[eval(n)!=0]

I learnt a new language feature today doing this! Conditionals via boolean indexing. I may have slightly overdone it.

I tried abstracting out the comprehensions, but I couldn't make it any shorter (196 bytes):

e=lambda s:[d+'0'*(len(s)-i-1) for i,d in enumerate(s) if eval(d)]
def f(n):x=n.split('.');a,b=(x+[''],x)[len(x)-1];return['0',"+".join(e(a)+['.'+d[::-1]for d in e(b[::-1])][::-1])][bool(eval(n))]

(Reversing sequences is expensive!)

Whilst mine is shorter for now, I think TanMath can golf his down to match mine: Using e=enumerate, replacing pass with 0, and using '0' in place of ['0'] in the return statement should save 4+3+2=9 bytes! Taking it down to 187. I'm sure another few bytes can be shaved off somewhere...

edit New approach (156 bytes). However, it can only deal with precision up to 6dp similar to @jimmy23013's CJam entry, so it fails the final test. I couldn't coerce it to print more 0s, maybe someone else can. Instead I used it as the basis of my best attempt yet, see top (Also, this approach prints the 0 before the decimal place, but that seems valid as well.). Took the try:... except:... approach from TanMath:

def f(n):
 *m,=n
 try:p=m.index('.');m.pop(p)
 except:p=len(m)
 return('0','+'.join([str(eval(d)*10**(p-i-1))for i,d in enumerate(m)if d!='0']))[eval(n)!=0] 

Ogaday

Posted 2016-01-09T01:35:12.643

Reputation: 471

If you are trying to give golfing help to me, please include them as comments to my answer, not in your answer. I do not always see your answers, so by writing a comment, I will get a notification and definitely see it. – TanMath – 2016-01-20T21:25:34.097

2Hi @TanMath. I would, but I don't have enough rep to comment on other people's posts yet. Once I get a few more upboats I'll make sure to leave feedback in comments. – Ogaday – 2016-01-20T23:33:53.083

2

Dyalog APL, 47 bytes

{×⍎⍵:1↓∊'+',¨0~⍨(⍎¨w)×10*(⍵⍳'.')-1+⍳≢w←⍵~'.'⋄0} 

Takes number in character vector form, e.g. '123'.

Examples:

      f←{×⍎⍵:1↓∊'+',¨0~⍨(⍎¨w)×10*(⍵⍳'.')-1+⍳≢w←⍵~'.'⋄0} 
      ↑⍕¨f¨,¨'0' '6' '0.99' '24601' '6.283' '900000.000009'
0                     
6                     
0.9 + 0.09            
20000 + 4000 + 600 + 1
6 + 0.2 + 0.08 + 0.003
900000 + 0.000009     

Notes:
○ The reason for the modified last example is that APL, like some of the other submissions, by default will switch to scientific notation for such extreme numbers.
○ The phrase ↑⍕¨f¨,¨ is only needed to process all examples at once.

Adám

Posted 2016-01-09T01:35:12.643

Reputation: 37 779

2

pure bash, 210

o= a=${1%.*} b=${1#$a};while [ "$a" ];do c=${a:1};((${a%$c}>0))&&o+=${a%$c}${c//?/0}+;a=$c;done;[ "$b" ]&&{ b=${b#.} a=;while [ "$b" ];do c=${b:0:1};((c>0))&&o+=.$a$c+;b=${b:1};a+=0;done;};o=${o%+};echo ${o:-0}

or

o= a=${1%.*} b=${1#$a};while [ "$a" ];do c=${a:1};((${a%$c}>0))&&
o+=${a%$c}${c//?/0}+;a=$c;done;[ "$b" ]&&{ b=${b#.} a=;while [ "$b" ]
do c=${b:0:1};((c>0))&&o+=.$a$c+;b=${b:1};a+=0;done;};o=${o%+};echo ${o:-0}

Test:

exp() {
    o= a=${1%.*} b=${1#$a};while [ "$a" ];do c=${a:1};((${a%$c}>0))&&
    o+=${a%$c}${c//?/0}+;a=$c;done;[ "$b" ]&&{ b=${b#.} a=;while [ "$b" ]
    do c=${b:0:1};((c>0))&&o+=.$a$c+;b=${b:1};a+=0;done;};o=${o%+};echo ${o:-0}
}
while read num;do
    printf "%-12s => " $num
    exp $num
done <<<$'0\n6\n0.99\n24601\n6.283\n9000000.0000009\n3.1415\n.99'
0            => 0
6            => 6
0.99         => .9+.09
24601        => 20000+4000+600+1
6.283        => 6+.2+.08+.003
9000000.0000009 => 9000000+.0000009
3.1415       => 3+.1+.04+.001+.0005
.99          => .9+.09

F. Hauri

Posted 2016-01-09T01:35:12.643

Reputation: 2 654

2

Python, 131 bytes

f=lambda s,k=0,i=0,o="",z="0":s and f(s[1:],(s<z)+k,i+k,o+(s>="1")*([s[0]+~-(s+".").find(".")*z,"."+z*i+s[0]][k]+"+"))or o[:-1]or z

A really, really messy recursive function, probably not the best way to go about this. Input like f("10.0203").

Sp3000

Posted 2016-01-09T01:35:12.643

Reputation: 58 729

Is this even Python? Love it. – Ogaday – 2016-01-26T14:38:46.753

2

C, 155 153 161 bytes

+2 to link in the math library (source itself is 159).

main(d,v,p,q)char**v,*p,*q;{for(p=strchr(q=v[1],46),d=p?p-q:strlen(q);*q;++q)*q^46?printf(*q^48|q==v[1]?"%.*f%c":"",d<0?-d:0,(*q-48)*pow(10,--d),q[1]?43:0):0;}

Ungolfed

int main(int d, char **v, char *p, char *q)
{
    for(q = v[1], /* Cache the input string */
        p = strchr(q,'.'), /* find the decimal */
        d = p ? p-q : strlen(q); /* calculate number of digits before decimal */
        *q; /* loop while still input data */
        ++q) /* iterate to next character */
    {
        *q^46 /* if not at the decimal point... */
            ? printf(*q^48 || q == v[1] /* if not a zero, or if the string itself is zero... */
                ? "%.f%c" /* print the digit */
                : "", /* else print nothing */
                d<0 ? -d : 0, /* Calculate number of places after decimal to print */
                (*q-48)*pow(10,--d), /* Calculate the digit at the desired power of 10 */
                q[1]?43:0) /* If the next character is still valid input, print the '+' */
            : 0 /* else, do nothing */
    }
}

Cole Cameron

Posted 2016-01-09T01:35:12.643

Reputation: 1 013

1

Stax, 18 bytes

ºî≤FlφLfÜG→\ΦUq╜♥←

Run and debug it

Unpacked, ungolfed, and commented, it looks like this.

c           copy input
!C          terminate if input is falsy
y{          for each character in the string input...
  y.\d'0R   replace each digit in the input with "0"
  ia&       then replace the nth character back to its original value
  e         eval as float
m           map using block to produce array
{f          filter out zeroes
'+*         join with "+"

Run this one

Like the many of the other solutions posted, it produces 9000000+9e-7 for the last test case. According to established precedent this is allowed because the test case is too precise for the language.

recursive

Posted 2016-01-09T01:35:12.643

Reputation: 8 616

1

Java, 284 244 243 Bytes

String x(String s){int b=s.length(),d=(d=s.indexOf(46))<0?b:d,i=-1,k=0;String o="";for(char c;++i<b;)o+=(c=s.charAt(i))>48?(k++>0?" + ":"")+(d-i>0?c:"0.")+new String(new char[Math.abs(d-i)-1]).replace('\0','0')+(d-i>0?"":c):"";return b<2?s:o;}

Unfortunately, I could not find a shorter way of creating repeating Strings than:

  • build a char[] of the required length
  • use Arrays.fill to set the characters
  • use new String so it can be concatenated

With inspiration by @Khaled A Khunaifer, I could shave off 40 Bytes.

Edit: indexOf takes an int, so I could replace '.' with 46. Unfortunately, this does not seem to be possible with replace.

ECS

Posted 2016-01-09T01:35:12.643

Reputation: 361

I managed to shrink it down to 250, check http://ideone.com/HqLnMo

– Khaled.K – 2016-01-19T09:21:21.193

@Khaled A Khunaifer Your solution seems to have problems with single digit test cases. But I like your way of generating the zeros. – ECS – 2016-01-19T09:39:23.030

fix this .replace('\0','0') function replace expect String not char, it should be .replace("\0","0") – Khaled.K – 2016-01-19T10:20:28.863

@Khaled A Khunaifer It works in my test cases, also https://docs.oracle.com/javase/8/docs/api/java/lang/String.html#replace-char-char-

– ECS – 2016-01-19T10:24:36.107

1

Retina, 113 bytes

Currently much longer than Martin's solution but uses a different method so I decided to post it.

^
x
S_`(?<=(.*)).(?=(.*))
x

¶\..*¶.*

$
¶
T`d`0`(?<=\d).*¶.*¶
(.*)¶(.*)¶
$2$1¶
(\..*?)0*¶
$1¶
\.?¶0*
¶
¶+
+
\+$
[empty line]

Try it online here.

randomra

Posted 2016-01-09T01:35:12.643

Reputation: 19 909

1

Perl, 248 bytes

Ew, I am noobish at Perl golfing.

@a=split/\./,<>;
@b=split``,$a[1];
@c=split``,$a[0];
for($i=0;$i<length$a[0];$i++){
   $_.=($c[$i]!=0)?$c[$i]."0"x((length$a[0])-$i-2)."+":"";
}
for($i=1;$i<=length$a[1];$i++){
   $_.=($b[$i-1]!=0)?"0."."0"x($i-1).$b[$i-1]."+":"";
}
chop;
($_=="")?print"0 ":print;

Try it here.

Paul Picard

Posted 2016-01-09T01:35:12.643

Reputation: 863

This seem not work with integer numbers. – F. Hauri – 2016-01-20T13:40:07.767

I put the wrong Ideone link. It doesn't take into account changes made in Edit mode. :( It should work now. – Paul Picard – 2016-01-20T13:54:55.450

You have an error somewhere: when I enter 5 it return 50. – F. Hauri – 2016-01-20T16:29:51.327

Strange, since I tested 5 with the link I provided yesterday after you put your first comment. Mind trying now ? (I changed the link again) – Paul Picard – 2016-01-21T09:26:35.257

I just tested your script on my perl interpreter (v5.20.2) – F. Hauri – 2016-01-21T13:44:15.773

Ah, figured it out : it's because Ideone ignores the trailing newline when something is in stdin, while executing the script inside the interpreter adds a trailing newline at the end of the input, adding 1 to the length of the array. Meh :c – Paul Picard – 2016-01-21T18:26:39.520

36 => 300+60! I've copied your script to a script file, added shebang #!/usr/bin/perl and run by: ./exp.pl <<<36;echo ... (work fine with floating: 3.62.=> 3+0.6+0.02) – F. Hauri – 2016-01-21T18:35:01.157

Changed a bit : ((length$a[0])-$i-2) instead of ((length$a[0])-$i-1) in the first loop. Should be ok now. (I could chomp the input, but it adds a lot more characters) – Paul Picard – 2016-01-21T21:25:02.497

Well now, this seem correct! +1 for debugging effort! – F. Hauri – 2016-02-03T07:49:46.847

1

perl, 132 bytes

131 +1 for -p switch.

This is based on my previous sed answer:

1while s/^([1-9]\d*)([1-9])(0*)([+.].*|)$/${1}0$3+$2$3$4/||s/([1-9]0*)\.([0-9])/$1+.$2/||s/\.(0*)([1-9])(\d*[1-9])$/.$1$2+.${1}0$3/

Test suite:

perl -pe'1while s/^([1-9]\d*)([1-9])(0*)([+.].*|)$/${1}0$3+$2$3$4/||
    s/([1-9]0*)\.([0-9])/$1+.$2/||s/\.(0*)([1-9])(\d*[1-9])$/.$1$2+.${1}0$3/
' <<<$'0\n6\n0.99\n24601\n6.283\n9000000.0000009\n3.1415'
0
6
0.9+.09
20000+4000+600+1
6+.2+.08+.003
9000000+.0000009
3+.1+.04+.001+.0005

F. Hauri

Posted 2016-01-09T01:35:12.643

Reputation: 2 654

1

Powershell - 172 166 193 bytes

All on a single line:

$z=([string]$args[0])-split"\.";$y=$z[0].length-1+0.6;($z|%{$x=[char[]]$_;if($y-gt0){($x|%{$_+"0"*(-1+$y--)})}else{($x|%{"0."+"0"*[math]::abs($y--)+$_})}}|?{-not($_-match'^[0.]+$')})-join' + '

Ungolfed:

$z=([string]$args[0]) -split "\."
$y=$z[0].length-1+0.6
($z | %{
    $x=[char[]]$_
    if($y -gt 0) {
        ($x | %{$_+"0"*(-1+$y--)})
    } else {
        ($x | %{"0."+"0"*[math]::abs($y--)+$_})
    }
} | ?{ -not($_ -match '^[0.]+$')}) -join ' + '

Test cases, plus one additional:

PS> (0, 6, 0.99, 24601, 6.283, 9000000.0000009, [math]::pi) | %{.\expand.ps1 $_}

6
0.9 + 0.09
20000 + 4000 + 600 + 1
6 + 0.2 + 0.08 + 0.003
9000000 + 0.0000009
3 + 0.1 + 0.04 + 0.001 + 0.0005 + 0.00009 + 0.000002 + 0.0000006 + 0.00000005 + 0.000000003 + 0.0000000005 + 0.00 000000008 + 0.000000000009 + 0.0000000000007 + 0.00000000000009    
PS>

Chris J

Posted 2016-01-09T01:35:12.643

Reputation: 199

Your regex filters out $args = 0. Here's a simple bug fix that also saves 3 bytes

– Veskah – 2019-07-08T19:28:56.890

172 bytes after a slight revamp – Veskah – 2019-07-08T19:46:08.123

1

CoffeeScript, 144 bytes

Straight forward solution:

X=(n)->[m,k]="#{n}".split '.';(c+Array(m.length-i).join 0for i,c of m when+c).concat(".#{Array(++i).join 0}"+c for i,c of k when+c).join('+')||0

Executable:

<script src="http://coffeescript.org/extras/coffee-script.js"></script>
<script type="text/coffeescript">
X=(n)->[m,k]="#{n}".split '.';(c+Array(m.length-i).join 0for i,c of m when+c).concat(".#{Array(++i).join 0}"+c for i,c of k when+c).join('+')||0

# Tests follow
tests = [
  0
  6
  0.99
  24601
  6.283
  9000000.0000009
]

window.solution = X
result.textContent=("#{n} => #{X n}" for n in tests).join '\n'
</script>
<input type="number" oninput="result.textContent=solution(this.value)">
<pre id="result"></pre>

metalim

Posted 2016-01-09T01:35:12.643

Reputation: 523

1

Python, 125 bytes

After deleting my 1st answer (sry!) which could not handle small numbers due to machine epsilon issues, I found a different solution. It handles float as well as integers, trailing zeros (!) and is written as function.

Thanks to @ogaday for the useful hints and for the compact '0'-fix!

Golfed:

def f(x):x+='.';i=x.find('.');z=list(x);del z[i];return'+'.join([str(int(o)*10**(i-j-1))for j,o in enumerate(z)if'0'<o])or'0'

Ungolfed:

def f(x):
  x+='.'
  i=x.find('.')
  z=list(x)
  del z[i]   
  return '+'.join([str(int(o)*10**(i-j-1)) for j,o in enumerate(z) if '0'<o]) or '0'

Usage:

>>> f("0")
'0'

>>> f("32.005")
'30+2+0.005'

>>> f("100020003000009000000.0007")
'100000000000000000000+20000000000000000+3000000000000+9000000+0.0007'

>>> f("1000000000009000000.0007000000000000000002")
'1000000000000000000+9000000+0.0007+2e-22'

>>> f("0001.99")
'1+0.9+0.09'

lambruscoAcido

Posted 2016-01-09T01:35:12.643

Reputation: 401

1Nice. Fails the f('0') test case however, and when I copy and paste straight into my interpreter I get the scientific notation (which I think is fine). Also, list(c) is shorter. If you concatenate the '.' before turning it into a list you don't need to add [] either. Using find instead of index on the string before turning it into a list, after adding '.' also saves you a byte. Reordering the inequality allows you to remove an additional space too: def f(x):x+='.';i=x.find('.');z=list(x);del z[i];return"+".join([str(int(o)*10**(i-j-1))for j,o in enumerate(z)if"0"<o])or'0' – Ogaday – 2016-01-26T15:24:04.513

0

C, 253 bytes

m(char*i){int k,j=0,s=0,d=0;while(i[s])s++;while(i[d]!=46)d++;while(j<d){if(i[j]!=48){for(k=0;k<(d-j);k++)putchar(k?48:i[j]);putchar(43);}j++;}while(++j<s)if(i[j]!=48){putchar(46);for(k=0;k<(j-d);k++)putchar(k==(j-d-1)?i[j]:48);putchar(43);}putchar(8);}

Note: putchar(8) should perform a backspace.

 Input: 1230.0456
Output: 1000+200+30+.04+.005+.0006

Detailed, try here

while(i[s]) s++;
while(i[d]!=46) d++;

while (j<d)
{
    if (i[j]!='0')
    {
        for(k=0;k<(d-j);k++) putchar(k? '0': i[j]);
        putchar(43);
    }
    j++;
}

while (++j<s)
if (i[j]!='0')
{
    putchar(46);
    for(k=0; k<(j-d); k++) putchar(k==(j-d-1)? i[j]: '0');
    putchar(43);
}

putchar(8);

Khaled.K

Posted 2016-01-09T01:35:12.643

Reputation: 1 435

0

Lua, 350 Bytes

I think there's two way to golf it down further :

  • I could make use of macro.define to replace some of the commons expressions (can't test right now, and not sure it would make me gain some bytes)

  • Use split on the dot instead of iterating on the whole string. Once again, I'm not sure it would reduce the size of this function, as manipulating string in lua is quite painful.

function f(s)v,r=s:find("%.")or#s+1,""if #s==1 then return s end for i=1,#s do a=""(v>i and s:sub(i,v-1)or s:sub(v,i)):gsub(".",function(c)a=a..(not a:find(c)and(c==s:sub(i,i)or c==".")and c or 0)end)s,r=v<i and s:sub(0,i-1).."0"..s:sub(i+1,#s)or s,r..((#a==a:find("%.")or tonumber(a)==0)and""or a:gsub("%.","0.")..(i~=#s and"+"or""))end return r end

Explanations

function f(s)
  v=s:find("%.")or #s+1               -- v=index of the dot in a decimal number
  r=""                                -- v=#s+1 when s is an integer(v=0 would screw sub())
  if #s==1 then return s end          -- exit if s is a single digit
  for i=1,#s                          -- iterate over s
  do
    a=""

    (v>i and s:sub(i,v-1)or s:sub(v,i)-- only send the integer OR decimal part to gsub
      ):gsub(".",function(c)          -- iterate over each character of s:sub()

    -- a contains the next number to be concatenated to the string r(the one to be returned)
      a=a..(not a:find(c)             -- we concatenate a with c if a doen't contains
        and(c==s:sub(i,i)or c==".")   -- c, and c is either a dot, or the next number
             and c or 0)              -- to be add, we put a 0 otherwise
    end)
    -- we concatenate the new a with the string already formed
    r=r..((#a==a:find("%.")           -- if a=="." or a's value is 0
            or tonumber(a)==0)and""   -- we concatenate an empty string
      or a:gsub("%.","0.")            -- else, we replace the (possible) leading dot by "0."
      ..(i~=#s and"+"or""))           -- and concatenate a "+" if it isn't the last number to be added

    s=v<i and s:sub(0,i-1)            -- We then replace the digit we have worked with
      .."0"..s:sub(i+1,#s)or s        -- to prevent duplicates
  end
  return r
end

You can test lua online and use the following source code to run it with some test cases

function f(s)v,r=s:find("%.")or#s+1,""if #s==1 then return s end for i=1,#s do a=""(v>i and s:sub(i,v-1)or s:sub(v,i)):gsub(".",function(c)a=a..(not a:find(c)and(c==s:sub(i,i)or c==".")and c or 0)end)s,r=v<i and s:sub(0,i-1).."0"..s:sub(i+1,#s)or s,r..((#a==a:find("%.")or tonumber(a)==0)and""or a:gsub("%.","0.")..(i~=#s and"+"or""))end return r end

print(f("3123.12333"))
print(f("9545"))
print(f("9000000.0000009"))
print(f("6"))

Katenkyo

Posted 2016-01-09T01:35:12.643

Reputation: 2 857

0

sed, 136 128 bytes

Reduced by 8 chars by dropping spaces and useless 0.

:;s/^([1-9][0-9]*)([1-9])(0*)([+.].*|)$/\10\3+\2\3\4/;s/([1-9]0*)\.([0-9])/\1+.\2/;s/\.(0*)([1-9])([0-9]*[1-9])$/.\1\2+.\10\3/;t

Test cases:

sed -r ':;
    s/^([1-9][0-9]*)([1-9])(0*)([+.].*|)$/\10\3+\2\3\4/;
    s/([1-9]0*)\.([0-9])/\1+.\2/;
    s/\.(0*)([1-9])([0-9]*[1-9])$/.\1\2+.\10\3/;
    t' <<<$'0\n6\n0.99\n24601\n6.283\n9000000.0000009\n3.1415'
0
6
0.9+.09
20000+4000+600+1
6+.2+.08+.003
9000000+.0000009
3+.1+.04+.001+.0005

F. Hauri

Posted 2016-01-09T01:35:12.643

Reputation: 2 654

0

R - 133 bytes

Robust, ignores Machine Epsilon and works also with trailing zeros.

a) Golfed:

f=function(x)if(x=='0')x else{z=strsplit(x,'')[[1]];i=which(z=='.');n=as.numeric(z[-i])*10^(i-seq(z)[-1]);paste(n[n>0],collapse='+')}

Ungolfed:

f=function(x)
  if(x=='0') 
    x 
  else {
    z=strsplit(x,'')[[1]]
    i=which(z=='.')   
    n=as.numeric(z[-i])*10^(i-seq(z)[-1])  
    paste(n[n>0],collapse='+')
  }

Usage:

f("900.008")

lambruscoAcido

Posted 2016-01-09T01:35:12.643

Reputation: 401

0

JavaScript (ES7), 114 bytes

s=>(p=s.search(/.\b/),i=-1,[for(c of s)if((i++,c>0))(z=s.substring(i,p).replace(/d/g,0),i<p?c+z:z+c)].join`+`||s

Works with arbitrary length numbers because it uses string manipulation throughout.

Without the array comprehension (122 bytes):

s=>[...s].map((c,i)=>c<'1'?'':(z=s.substring(i,p).replace(/\d/g,0),i<p?c+z:z+c),p=s.search(/.\b/)).filter(x=>x).join`+`||s

Ungolfed:

function expand(s) {
    zeros = s.replace(/\d/g, "0");
    point = s.indexOf(".");
    if (point < 0) point = s.length;
    result = [];
    for (i = 0; i < s.length; i++) {
        if (s[i] > "0") {
            if (i < point) result.push(s[i] + zeros.slice(i, point - 1));
            else result.push(zeros.slice(point - 1, i) + s[i]);
         }
     }
     return result.length ? result.join("+") : s;
}

Neil

Posted 2016-01-09T01:35:12.643

Reputation: 95 035

As far as I know, this new array comprehension syntax is from ECMAScript 7. – manatwork – 2016-01-22T11:11:53.000

@manatwork Thanks, I updated it while I was adding the ungolfed version. – Neil – 2016-01-22T11:20:27.690