4
\$\begingroup\$

Write a program that converts a mathematical expression to words, evaluates the expression, and prints how the equation would be spoken aloud.

Input

  • The input must only contain numbers and the symbols +, -, *, and /. There cannot be any whitespace in the input.
  • The input does not say what the expression is equal to.

Output

  • While order of operations must be followed in determining the numerical answer in the expression, it is not necessary to indicate this in the output (for this reason, the input cannot contain parentheses).
  • Numbers must be printed in capital letters. Operations must be printed in lower case.
  • Numbers must be printed in the order that they appear in the input. Then the word equals must be printed, then the answer.
  • Numbers in the output can be negative. The word negative is written in capital letters.
  • Operations and numbers must be separated by a space. There cannot be any space after the last letter is printed.
  • + in the input gets converted to plus in the output. - in the input gets converted to minus in the output. * in the input gets converted to times in the output. / in the input gets converted to divided by in the output.
  • Division by 0 is not allowed.
  • When division results in a decimal, the number should be rounded to three decimal places and read X POINT X X X where the Xs are replaced by numbers.
  • Negative numbers should have `NEGATIVE in front of them.
  • For simplicity, all numbers must have absolute value less than 1000.
  • 0 is ZERO (not NOUGHT, OH, etc).

Samples

Inputs

1+2
2-3
6*2-4/1
1+1-1*1/1
2/3
413-621

Outputs

ONE plus TWO equals THREE
TWO minus THREE equals NEGATIVE ONE
SIX times TWO minus FOUR divided by ONE equals EIGHT
ONE plus ONE minus ONE times ONE divided by ONE equals ONE
TWO divided by THREE equals ZERO POINT SIX SIX SEVEN
FOUR HUNDRED THIRTEEN minus SIX HUNDRED TWENTY-ONE equals NEGATIVE TWO HUNDRED EIGHT

This is code golf, fellas. Standard CG rules apply. Shortest code in bytes wins.

\$\endgroup\$
11
  • \$\begingroup\$ Is there a limit to the size of the numbers? Are decimals to be handled and if so to what precision? \$\endgroup\$
    – MickyT
    Sep 21, 2015 at 2:55
  • \$\begingroup\$ How do you get TWO for the last example? I get 1+1-1*1/1=1 \$\endgroup\$
    – Geobits
    Sep 21, 2015 at 2:56
  • \$\begingroup\$ @MickyT Updated. \$\endgroup\$
    – Arcturus
    Sep 21, 2015 at 2:58
  • 9
    \$\begingroup\$ Also, do we have to handle numbers greater than 9? How do we output those? ONE NINE or NINETEEN? What is the maximum number we will have to handle? \$\endgroup\$
    – DankMemes
    Sep 21, 2015 at 3:36
  • 4
    \$\begingroup\$ @Eridan I think it's to late to update. That's probably invalidated every answer \$\endgroup\$
    – Downgoat
    Sep 21, 2015 at 14:30

5 Answers 5

4
\$\begingroup\$

JavaScript ES6, 255 247 237 225 219 bytes

s=>(s+'='+ +eval(s).toFixed(3))[h=(a,b,l)=>' '+[a,...btoa(b).split`z`][l],t='replace'](/\D/g,l=>h('divided by',`¶)³:eºÌæ{¬Íê®j[3¦§·<`,'*+-/=.'.indexOf(l)))[t](/\d/g,l=>h('ZERO',`8Ñ3Mc³LtD1NQÅ!Q3HóHED71tó4D`,l))

I'll resume golfing tomorrow. Gotta sleep :/

Base encoding may cause issues. If it does, I'll add a pastebin and possibly a hex dump.

If you find any issues (or the spec changes) don't hesitate to tell me, I'll fix it as soon as possible.

Explanation

s=>     // Function with argument "s"
 (s+'='                  // Add an equal sign to the input
   + +eval(s).toFixed(3)    // Add the value of the expression rounded to 3 places
 )[h=(a,b,l)=>           // Function h with args a,b, and l
                         // Return...
     ' '+                    // A space added to...
     [a,...btoa(b).split`z`] // Base decode the compressed words
     [l]                     // Grab the correct word
  ,t='replace'            // Alias replace command

 ](/\D/g,                // Replace non-digits with...
    l=>h(                                   // Function h
       'divided by',`¶)³:eºÌæ{¬Íê®j[3¦§·<`, // Base encoded words
       '*+-/=.'.indexOf(l)                  // Replace operator with correct word
    )

 )[t](                             // Replace again
    /\d/g,l=>                      // Replaces Digits with...
      h('ZERO',`8Ñ3Mc³LtD1NQÅ!Q3HóHED71tó4D` // Base encoded words
        ,l                                   // The associated number
      )
 )
\$\endgroup\$
1
\$\begingroup\$

Python 3, 268 224bytes

a=input()
o=eval(a)
print(*[{i:j for i,j in zip('*+-./=1234567890','times,plus,minus,POINT,divided by,equals,ONE,TWO,THREE,FOUR,FIVE,SIX,SEVEN,EIGHT,NINE,ZERO'.split(','))}[i] for i in a+'='+('%.'+str(3*(int(o)!=o))+'f')%o])

A dictionary lookup for each item assuming numbers are only evaluated between 0-9. Would appreciate some feedback on this.

Explanation:

The following formats the output string with the required decimals based on the fact that in python integers evaluate as equal to the equivalent float. e.g. 1.0 == 1 Which I use to identify integer numbers.

('%.'+str(3*(int(o)!=o))+'f')%o
('%.0f')%o if o is an integer
('%.3f')%o if o is a decimal

edit: Dictionary generators!

\$\endgroup\$
2
  • \$\begingroup\$ 13+468-1966 returns ONE THREE plus FOUR SIX EIGHT minus ONE NINE SIX SIX equals minus ONE FOUR EIGHT FIVE instead of THIRTEEN plus FOUR HUNDRED SIXTY-EIGHT minus ONE THOUSAND NINE HUNDRED SIXTY-SIX equals NEGATIVE ONE THOUSAND FOUR HUNDRED EIGHTY-FIVE \$\endgroup\$
    – RK.
    Sep 21, 2015 at 20:23
  • \$\begingroup\$ Yeah... The rules changed overnight... Probably adds quite a few bytes regardless. \$\endgroup\$
    – Todd
    Sep 22, 2015 at 6:43
1
\$\begingroup\$

Pyth, 170 143 141 bytes

jdm@c"ZERO,ONE,TWO,THREE,FOUR,FIVE,SIX,SEVEN,EIGHT,NINE,plus,minus,times,divided by,POINT,equals"\,x+jkm`kUT"+-*/.="d++z\=?q>2J`.Rvz3".0"<2JJ

Evaluates the input and if it ends with ".0", strips it. Then loops through a list with the numbers, then looks with their word representation.

\$\endgroup\$
5
1
\$\begingroup\$

Python 2, 281 223 221 219 + 5 bytes

run with: "python -Qnew golf.py" to enable float divisions

a=raw_input()
print" ".join("ZERO%ONE%TWO%THREE%FOUR%FIVE%SIX%SEVEN%EIGHT%NINE%NEGATIVE%times%plus%equals%minus%POINT%divided by".split("%")[ord(i)-48]for i in a+','+("%.3f"%eval(a)).replace("-",")").replace(".000",""))

4 bytes off thanks to Zach Gates

\$\endgroup\$
5
  • 1
    \$\begingroup\$ You can remove the spaces around your modulo operator. It saves 2 bytes. \$\endgroup\$
    – Zach Gates
    Sep 21, 2015 at 14:11
  • 1
    \$\begingroup\$ You can also remove the r (that makes it a raw string) from in front of your (\d+) regex string. And the first and last bracket inside the " ".join, because you can pass the iterable as an argument. \$\endgroup\$
    – Zach Gates
    Sep 21, 2015 at 14:14
  • 1
    \$\begingroup\$ changed a lot before reading your comment :P \$\endgroup\$
    – Max
    Sep 21, 2015 at 14:23
  • \$\begingroup\$ What about the teens? \$\endgroup\$
    – RK.
    Sep 21, 2015 at 20:24
  • \$\begingroup\$ The OP changed the rules after the game has started... to spell the numbers in english words is another CG! \$\endgroup\$
    – Max
    Sep 22, 2015 at 6:31
0
\$\begingroup\$

Python 2, 628 + 5 bytes

run with: "python -Qnew golf.py" to enable float divisions

this one should spell correctly the numbers

import re
a=raw_input()
d,x="ZERO%ONE%TWO%THREE%FOUR%FIVE%SIX%SEVEN%EIGHT%NINE%TEN%ELEVEN%TWELVE%THIR%FOUR%FIF%SIX%SEVEN%EIGH%NINE%TWENTY%THIRTY%FORTY%FIFTY%SIXTY%SEVENTY%EIGHTY%NINETY%NEGATIVE%times%plus%equals%minus%POINT%divided by".split("%"),[]
for i in re.split("([.),/*+-])",a+','+("%.3f"%eval(a)).replace("-",")").rstrip('0').rstrip('.')):
    r=""
    if len(i)>2:
        x+=[d[int(i)//100],"HUNDRED"];i=i[1:].lstrip("0")
    if len(i)>1:
        z=int(i)
        if z<20:r+=d[z]+["","TEEN"][z>12];i=""
        else:r+=d[z//10+18]+["-",""][i[1]<"1"];i=i[1].strip("0")
    if i:
        c=d[ord(i)-48]
        if i<"0":x+=[c]
        else:r+=c
    if r:x+=[r]
print" ".join(x)

Test

1+2
ONE plus TWO equals THREE
2-3
TWO minus THREE equals NEGATIVE ONE
6*2-4/1
SIX times TWO minus FOUR divided by ONE equals EIGHT
1+1-1*1/1
ONE plus ONE minus ONE times ONE divided by ONE equals ONE
2/3
TWO divided by THREE equals ZERO POINT SIX HUNDRED SIXTY-SEVEN
413-621
FOUR HUNDRED THIRTEEN minus SIX HUNDRED TWENTY-ONE equals NEGATIVE TWO HUNDRED EIGHTEEN
\$\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.