# How can I used fixed-point arithmetic to convert from Celsius to Fahrenheit?

Disclaimer: I realize this is not the easiest or even best way to handle this and I am asking largely out of a sense of curiosity, not because I'm convinced this is the proper way. It's a fun puzzle I've been wrestling with for a day or so now and can't figure out (and can't seem to find a good answer online either!)

I'm working on a project with my Arduino (but this could apply to any hardware) which involves sensing temperature. I get the value, parse it, and have it stored in Celsius with a 1/100 scaling factor. e.g. the value 5.34C is stored in memory as the `uint16_t 534`. Thus printing this value is a matter of `print (temp / 100 + "." + temp % 100)`. When I use it for logic in my program I need only compare it against another value with a 1/100 scaling factor and everything works great.

Let's pretend my Arduino or whatever system had no support for floating point numbers and I only had integers. How can I convert this number to Fahrenheit? I've tried several times to work it out on paper and it seems right but I always get an incorrect result when testing.

• Note that `5.34 / 5 * 9 + 32` is `41.61` and `534 / 5 * 9 + 32` is `4161` Jun 19 '18 at 23:20
• Fixed point is great for hiding part of the problem of exact representation of base 10 decimal values, but you still cannot represent 1/3, 1/7, 1/11, basically any x/p where p prime and not p divides x. And beware the precision beast, it will bite you. Jun 20 '18 at 0:17

Multiply first, then divide; that will hide the integer round off error more:

in floating point (most accurate):

``````534.0 / 5.0 * 9.0 + 32.0 = 41.612
``````

in integer arithmetic

``````534 / 5 * 9 + 3200 = 4154 (or 41.54 after scaling back)
``````

because `534/5 = 106`, in integer arithmetic, instead of `106.8`; this round off error is then multiplied (magnified by multiplication), which accounts for the `41.54` vs `41.61` that we want.

How can I convert this number to Fahrenheit?

Multiplying first, then dividing:

``````534 * 9 / 5 + 3200 = 4161 (or 41.61 after scaling back)
``````

alternatively, you can

• scale up higher for the conversion, e.g. 1/1000 instead of 1/100

• round up before the division, e.g. add 2 (or 3) before dividing by 5:

``````(534+2) / 5 * 9 = 4163 (or 41.63 after scaling back)
``````

Combining the "multiply first", and "the round up before divide" is reasonable:

``````(534 * 9 + 2) / 5 = 4161 (or 41.61 after scaling back)
``````

And finally, combining all of the above (scaling to 1/1000, using multiply first, and round before divide):

``````(534 * 900 + 25) / 50 + 32000 = 41612 (or 41.612)
``````

NOTE: this is not advocating fixed point arithmetic, per se — but rather just working a formula with the scaled number.  Truer to fixed point arithmetic would suggest `534 / 500 * 900 + 3200 = 4100`.  (This would also benefit from multiply-first: `534 * 900 / 500 + 3200 = 4161`.)

• Once you go to fixed point, usually you want to use a larger number of bits for an intermediate result (after the multiplication) and check for overflow at some point when scaling back down. The integer byte size was not specified, but this is something we should always watch out for. Jun 19 '18 at 23:57
• @FrankHileman, yes, good -- something to bear in mind! 32000, for example, is terribly close to the limit of a 16-bit signed integer; you'd want 32-bit arithmetic (and perhaps still check for/guard against overflow). Jun 19 '18 at 23:59
• You can implement multi-word integer calculations (add/sub easy, mul/div harder) and even make the integer representations dynamic length :-) Jun 20 '18 at 0:13
• @ChuckCottrill That is an alternative to fixed point. Jun 20 '18 at 18:00
• Thank you, my error was failing to also convert the +32 portion to +3200. Simple in retrospect but it goes to show that floats were invented for a reason. :) Jun 20 '18 at 18:35