DEV Community

C. Plug
C. Plug

Posted on

The round function and the 'negative zero.'

I wrote this post at qiita.com. I thought I'll share my epic fail here as well.

Another epic fail I made.

This is a story of me getting mocked by floating point numbers by not reading the document thoroughly. How many times do I have to stress that I should read the docs carefully?!!!??

If you know very well about floating point numbers, you can either skip this post or mock my total idiocy. If you don't know what I'm talking about, this post might help you in the future.

But this is not the 0.1 + 0.2 != 0.3 problem.

Problematic Temperature

I was making a web app where I had to embed some weather forecast using OpenWeatherMap.
API for OWM has tons of info, most of which I don't need. I had to make an array containing what I needed. Hopefully, somebody made a wrapper called OpenWeatherMap-PHP-API.

And some values returned by APIs turned out to be problematic. Below are the samples of data they return.

"temp":{
    "day":15.2,
    "min":10.11,
    "max":15.2,
    "night":10.11,
    "eve":15.04,
    "morn":15.2
},
Enter fullscreen mode Exit fullscreen mode

I only need min and max. They stand for 'minimum temp' and 'maximum temp' respectively. When PHP reads this JSON, it stores the values as float.
Due to space restrictions, I wanted to show them in integers, so I tried rounding them off.

The round function (float round ( float $val [, int $precision = 0 [, int $mode = PHP_ROUND_HALF_UP ]] )) was what I needed. This function will round the values off into integers ...or so I thought.

The fail

What will happen if I rounded the values above? Let's say we stored the decoded JSON object in $data.

round($data['temp']['max']) // => 15
round($data['temp']['min']) // => 10
Enter fullscreen mode Exit fullscreen mode

Pretty standard, eh?

However, I live in a place where it snows in winter. Let's run this code sometime between Autumn and Winter, or between Winter and Spring.

The JSON I'd get looks like this:

"temp":{
    "min":-0.44,
    "max":4.15,
},
Enter fullscreen mode Exit fullscreen mode

aaaaaand:

round($data['temp']['max']) // => 4
round($data['temp']['min']) // => -0 <- WTF?
Enter fullscreen mode Exit fullscreen mode

Damnit PHP?

You might have heard about 0.1 + 0.2 != 0.3 in the computer world. The 'glitch' is yet another specification of floating point numbers. 1 That's how they work!

Wait, what did the PHP manual say about the float function?

float round ( float $val [, int $precision = 0 [, int $mode = PHP_ROUND_HALF_UP ]] )
Enter fullscreen mode Exit fullscreen mode

float round.

float.

Deal with it m8, it's your epic fail.

How I solved it

Since rounded number initially being negative didn't matter for my use case, I cast the return to int. (I could've also ditch round and directly cast them to int.)

(int)round($data['temp']['min']) // => 0
Enter fullscreen mode Exit fullscreen mode

  1. Yet, PHP output the value that looks like an integer which probably confused me. Why is this the case? 

Top comments (1)

Collapse
 
david_j_eddy profile image
David J Eddy

You are not the only one who has seen PHP output -0 ;).

Sounds like a perfect situation to wrong up some unit tests to prevent regression later down the road.

RTFM gets me every time as well.