Isn't the point of math to just use numbers?
JavaScript ES6, 255 247 237 225 219 bytes

s=&gt;(s+'='+ +eval(s).toFixed(3))[h=(a,b,l)=&gt;' '+[a,...btoa(b).split`z`][l],t='replace'](/\D/g,l=&gt;h('divided by',`¶)³:eºÌæ{¬Íê®j[3¦§·&lt;`,'*+-/=.'.indexOf(l)))[t](/\d/g,l=&gt;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=&gt;     // 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)=&gt;           // 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=&gt;h(                                   // Function h
       'divided by',`¶)³:eºÌæ{¬Íê®j[3¦§·&lt;`, // Base encoded words
       '*+-/=.'.indexOf(l)                  // Replace operator with correct word
    )

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