The round function and the 'negative zero.'

clpsplug

C. Plug

Posted on October 30, 2018

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? 

💖 💪 🙅 🚩
clpsplug
C. Plug

Posted on October 30, 2018

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related