Programming Puzzles & Code Golf Stack Exchange is a question and answer site for programming puzzle enthusiasts and code golfers. It's 100% free, no registration required.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

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
share|improve this question
20  
+1 for "Since first-graders have short attention spans, your code will have to be as short as possible." – Downgoat Jan 9 at 1:42
2  
@Doᴡɴɢᴏᴀᴛ glad to see the meme is still running. – cat Jan 9 at 4:52
4  
It 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 Jan 18 at 12:14
2  
@jimmy23013 Yes, as long as it works in theory. – NinjaBearMonkey Jan 18 at 14:07
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 Jan 22 at 13:12

26 Answers 26

up vote 6 down vote accepted

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.
share|improve this answer
    
Based on the same idea: r_ee\'0fe<f{\~t~}{},'+*0e|. – jimmy23013 Jan 21 at 19:41
    
@jimmy23013 Wow, that is short! Thank you! – Dennis Jan 21 at 20:11

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>

share|improve this answer
    
Math.floor => 0|...? – ETHproductions Jan 10 at 22:54
    
@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 Jan 10 at 23:22
    
Can you use 0|Math.log10(n),p-=p<0 instead of Math.floor(Math.log10(n))? – Dom Hastings Jan 19 at 9:57
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 Jan 19 at 22:32
    
@DomHastings Still wouldn't work for n=0.1 anyway. – Neil Jan 20 at 20:50

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.

share|improve this answer

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!

share|improve this answer
2  
I think o if o else ["0"] can be o or["0"]. – lirtosiast Jan 19 at 3:06
    
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 Jan 21 at 10:26

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?

share|improve this answer

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))
share|improve this answer

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
share|improve this answer
    
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 Jan 25 at 20:32
1  
Just discovered it... I'm going to have to try not to spend too much time on this site! – speedplane Jan 25 at 22:11

Mathematica, 81 bytes

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

Test case:

%[101.01]
(* 100. + 1. + 0.01 *)
share|improve this answer
3  
I don't think having the decimal point over the integer parts is allowed. – Martin Ender Jan 18 at 11:33

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.
share|improve this answer

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] 
share|improve this answer
    
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 Jan 20 at 21:25
2  
Hi @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 Jan 20 at 23:33

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
share|improve this answer

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

share|improve this answer
    
Is this even Python? Love it. – Ogaday Jan 26 at 14:38

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 */
    }
}
share|improve this answer

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.

share|improve this answer

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.

share|improve this answer

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
share|improve this answer

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.

share|improve this answer
    
This seem not work with integer numbers. – F. Hauri Jan 20 at 13:40
    
I put the wrong Ideone link. It doesn't take into account changes made in Edit mode. :( It should work now. – Paul Picard Jan 20 at 13:54
    
You have an error somewhere: when I enter 5 it return 50. – F. Hauri Jan 20 at 16:29
    
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 Jan 21 at 9:26
    
I just tested your script on my perl interpreter (v5.20.2) – F. Hauri Jan 21 at 13:44

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.

share|improve this answer
    
I managed to shrink it down to 250, check ideone.com/HqLnMo – Khaled.K Jan 19 at 9:21
    
@Khaled A Khunaifer Your solution seems to have problems with single digit test cases. But I like your way of generating the zeros. – ECS Jan 19 at 9:39
    
fix this .replace('\0','0') function replace expect String not char, it should be .replace("\0","0") – Khaled.K Jan 19 at 10:20
    
@Khaled A Khunaifer It works in my test cases, also docs.oracle.com/javase/8/docs/api/java/lang/… – ECS Jan 19 at 10:24

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'
share|improve this answer
1  
Nice. 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 Jan 26 at 15:24

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"))
share|improve this answer

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);
share|improve this answer

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
share|improve this answer

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>
share|improve this answer

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;
}
share|improve this answer
    
As far as I know, this new array comprehension syntax is from ECMAScript 7. – manatwork Jan 22 at 11:11
    
@manatwork Thanks, I updated it while I was adding the ungolfed version. – Neil Jan 22 at 11:20

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")
share|improve this answer

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>

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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