Why do I get different results for the same values sent to a PHP function?

Asked

Viewed 55 times

0

I need to turn HOUR into DECIMAL and then do the opposite operation. I created the functions as shown below, but the result was not efficient because, depending on the origin of the value, the result is different, even being the same Type.

Follows the Code:

<?php
// Nutro as variáveis com o mesmo valor e o mesmo tipo de Type
// Mas uma de forma direta e outra via uma function.
$A = 1.01694444444; // Esta dá o retorno errado da function Func_1
$B = Func_2('01:01:01'); // Esta dá o retorno correto da function Func_1

echo $A . '<br />' . $B;

echo "<br /><br />";

// Mas o resultado dos cálculos da function abaixo é diferente
echo Func_1($A) . '<br />' . Func_1($B);

function Func_2($time){
   $hms = explode(":", $time);
   return ($hms[0] + ($hms[1]/60) + ($hms[2]/3600));
}

function Func_1($dec){
   $seconds = ($dec * 3600);
   $hours = floor($dec);
   $seconds -= $hours * 3600;
   $minutes = floor($seconds / 60);
   $seconds -= $minutes * 60;
   return lz($hours).":".lz($minutes).":".lz($seconds);
} 

function lz($num){
   return (strlen($num) < 2) ? "0{$num}" : $num; 
}
?>

I’ve looked everywhere, but I don’t know how to fix it. Follow a LINK from the example above: https://puffgestor.com.br/problema.php

  • Gave a var_dump at every step to see? Tried to force variable type? Apparently it’s just rounding/precision.

  • Basically the problem is to be working with floating point. You will need a round( $seconds ) to compensate. If you need accuracy, you shouldn’t be working with float

  • I’ve tried everything. I have no idea what’s going on. If I call the function like this: $A = 1.01694444444; Func_1('.'$A..'); Putting single quotes, it works. But in the same way, it doesn’t work if the value comes from the database.

  • I was doing this @Bacco: $seconds = round($seconds);

  • @Exact Rbz is like "solve". But as long as Jethro is using this scale, it’s just a palliative. It would be better to work with value in whole seconds instead of hours.

  • @Bacco, I’ve tried. I can’t round off why I would change the seconds in the conversion to HHMMSS.

  • 1

    @Jetrobernard only changed line 20 https://ideone.com/d2dkA1 - test with various values.

  • @Bacco, but if you do it at the end as in my answer, would it still be in the way? I guess I didn’t see the scale problem...

  • @Bacco WORKED !!! Thank you, friend. I had tried to round up on line 25, on the return of the Function lz of the Conds, but it did not function. Thank you very much, Beast.

  • See here a more extensive test to evaluate: https://ideone.com/RM1fTK

  • On line 25 it is no use to make the round because you are still using the $second on behalf of -=, so you’re subtracting the floating from the other rounded.

  • @Rbz exactly. Thanks, buddy. For the help.

Show 7 more comments

2 answers

3

As I had already posted in the comments, it is a rounding problem caused by the use of float.

I suggest changing this way:

function Func_1($dec){
   $seconds = round($dec * 3600); // <---- acrescentado o round
   $hours = floor($dec);
   $seconds -= $hours * 3600;
   $minutes = floor($seconds / 60);
   $seconds -= $minutes * 60;
   return lz($hours).":".lz($minutes).":".lz($seconds);
} 

See working on IDEONE.

Using the split rest operator (%) and the formatting function sprintf can simplify a little, and eliminate the function lz completely:

function Func_1($dec){
   $s       = round($dec*3600);
   $hours   = floor($dec);
   $minutes = floor(($s%3600)/60);
   $seconds = $s%60;
   return sprintf('%02d:%02d:%02d', $hours, $minutes, $seconds);
} 

function Func_2($time){
   $hms = explode(":", $time);
   return $hms[0] + $hms[1]/60 + $hms[2]/3600;
}

See working on IDEONE.

Here’s a little theory that might help you understand:

What is the correct way to use the float, double and decimal types?

2

In the method function Func_2() you just treat whole.

In the method Func_1() you are making calculations with a value floating (float, double, real).


A solution option is to round the decimals of seconds:

$seconds = round($seconds);


function Func_1($dec){
   $seconds = ($dec * 3600);
   $hours = floor($dec);
   $seconds -= $hours * 3600;
   $minutes = floor($seconds / 60);
   $seconds -= $minutes * 60;
   $seconds = round($seconds);
   return lz($hours).":".lz($minutes).":".lz($seconds);
}

Added in the value of $seconds already with all calculations to avoid previous error.


If it doesn’t work, show us the flaw to treat!

Browser other questions tagged

You are not signed in. Login or sign up in order to post.