Hi Guys
New to the forum and probably going to ask more questions than I could answer unfortunately as only have basic knowledge of php.
I have a problem with a bit of code that keeps rounding the 2'nd decimal place up. I'm trying to prevent it doing this but as yet still no luck. I am running PHP : 5.2.12. Would be grateful if anyone could point me in the right direction to stop it doing this. Basically we are trying to get it to invoice $1.134 but it is rounding up to $1.13 which when we mutliply it per product is a way off the correct total. I assume (almost certain) it is in the code below. Does anyone know what I could do to stop it doing this... Would be more than happy to make a donation to the forum or individual.
Cheers
Graeme
//Replacement for PHP's crud number_format/round functions which round down for even numbers on Linux
//This one rounds up whether odd or even, as it should!!
function format_number($float, $decimal_places = null, $format_negative = false, $suppress_commas = true, $negative_in_brackets = true)
{
if ($decimal_places === null)
{
$decimal_places = 4; //TODO: Load from config
}
else
{
$decimal_places = intval($decimal_places);
}
if (nbf_globals::$system_locale)
{
@setlocale(LC_ALL, nbf_globals::$system_locale); //You could force this to a different locale here if your system default one is not right
}
$is_negative = $float < 0;
if ($is_negative)
{
$float = abs($float);
}
$str_float = str_replace(",", ".", $float . ""); //Convert float to string, and if locale indicates a comma decimal separator, replace with dot
if (strpos($str_float, ".") !== false && substr($str_float, strlen($str_float) - 1) == '5')
{
$float += 0.00001;
}
$ret_val = $float;
if ($is_negative)
{
$ret_val = 0 - $ret_val;
}
if ($suppress_commas)
{
$thousands = "";
}
else
{
$thousands = ",";
}
$ret_val = number_format($ret_val, $decimal_places, ".", $thousands);
if ($format_negative)
{
if ($ret_val < 0)
{
if ($negative_in_brackets)
{
$ret_val = "<span style=\"color:#ff0000;\">(" . str_replace("-", "", $ret_val) . ")</span>";
}
else
{
$ret_val = "<span style=\"color:#ff0000;\">$ret_val</span>";
}
}
}
if (!$suppress_commas && $format_negative && function_exists("localeconv")) //Only applied to HTML output (invoices/reports)
{
$locale_info = localeconv();
if (strlen(@$locale_info['mon_thousands_sep']) > 0 && strlen(@$locale_info['mon_thousands_sep']) < 4)
{
$ret_val = str_replace(",", "!!#!!", $ret_val); //In case decimal point becomes comma
}
if (strlen(@$locale_info['mon_decimal_point']) > 0 && strlen(@$locale_info['mon_decimal_point']) < 4)
{
$ret_val = str_replace(".", @$locale_info['mon_decimal_point'], $ret_val);
}
if (strlen(@$locale_info['mon_thousands_sep']) > 0 && strlen(@$locale_info['mon_thousands_sep']) < 4)
{
$ret_val = str_replace("!!#!!", @$locale_info['mon_thousands_sep'], $ret_val);
}
}
//Revert back to default US locale so that database inserts are not messed up by unexpected commas
@setlocale(LC_ALL, "en_US", "en-US", "en", "English_United States", "en_US.UTF-8");
return $ret_val;
}
//The following functions are based on code in the public domain (PHP user comments)
function float_cmp($f1, $f2, $precision = null) // are 2 floats equal
{
if ($precision == null)
{
$precision = 3; //TODO: Load from config
}
$f1 = $f1 ? $f1 : 0;
$f2 = $f2 ? $f2 : 0;
$e = pow(10, $precision);
$first = $f1 * $e;
$second = $f2 * $e;
//Handle exponential notation
if (strpos($first, "E") !== false)
{
$first = sprintf("%d", $first);
}
if (strpos($second, "E") !== false)
{
$second = sprintf("%d", $second);
}
$i1 = intval((string)$first);
$i2 = intval((string)$second);
return ($i1 == $i2);
}
function float_gtr($big, $small, $precision = null) // is one float bigger than another
{
if ($precision == null)
{
$precision = 3; //TODO: Load from config
}
$big = $big ? $big : 0;
$small = $small ? $small : 0;
$e = pow(10, $precision);
$first = $big * $e;
$second = $small * $e;
//Handle exponential notation
if (strpos($first, "E") !== false)
{
$first = sprintf("%d", $first);
}
if (strpos($second, "E") !== false)
{
$second = sprintf("%d", $second);
}
$ibig = intval((string)$first);
$ismall = intval((string)$second);
return ($ibig > $ismall);
}
function float_gtr_e($big, $small, $precision = null) // is on float bigger or equal to another
{
if ($precision == null)
{
$precision = 3; //TODO: Load from config
}
$big = $big ? $big : 0;
$small = $small ? $small : 0;
$e = pow(10, $precision);
$first = $big * $e;
$second = $small * $e;
//Handle exponential notation
if (strpos($first, "E") !== false)
{
$first = sprintf("%d", $first);
}
if (strpos($second, "E") !== false)
{
$second = sprintf("%d", $second);
}
$ibig = intval((string)$first);
$ismall = intval((string)$second);
return ($ibig >= $ismall);
}
function float_add($f1, $f2, $precision = null) //Add 2 floats together (return as string)
{
if ($precision == null)
{
$precision = 3; //TODO: Load from config
}
$f1 = $f1 ? $f1 : 0;
$f2 = $f2 ? $f2 : 0;
$e = pow(10, $precision);
$first = $f1 * $e;
$second = $f2 * $e;
//Handle exponential notation
if (strpos($first, "E") !== false)
{
$first = sprintf("%d", $first);
}
if (strpos($second, "E") !== false)
{
$second = sprintf("%d", $second);
}
$result = intval((string)$first) + intval((string)$second);
$is_negative = $result < 0;
$result = str_pad(abs($result), 3, "0", STR_PAD_LEFT);
$result = $is_negative ? "-" . $result : $result;
$result = substr($result, 0, strlen($result) - $precision) . "." . substr($result, strlen($result) - $precision);
return $result;
}
function float_subtract($minuend, $subtrahend, $precision = null) //Subtract subtrahend from minuend (return string)
{
if ($precision == null)
{
$precision = 3; //TODO: Load from config
}
$minuend = $minuend ? $minuend : 0;
$subtrahend = $subtrahend ? $subtrahend : 0;
$e = pow(10, $precision);
$first = $minuend * $e;
$second = $subtrahend * $e;
//Handle exponential notation
if (strpos($first, "E") !== false)
{
$first = sprintf("%d", $first);
}
if (strpos($second, "E") !== false)
{
$second = sprintf("%d", $second);
}
$result = intval((string)$first) - intval((string)$second);
$is_negative = $result < 0;
$result = str_pad(abs($result), 3, "0", STR_PAD_LEFT);
$result = $is_negative ? "-" . $result : $result;
$result = substr($result, 0, strlen($result) - $precision) . "." . substr($result, strlen($result) - $precision);
return $result;
Some help regarding rounding
Moderator: General Moderators
- greyhoundcode
- Forum Regular
- Posts: 613
- Joined: Mon Feb 11, 2008 4:22 am
Re: Some help regarding rounding
What we can't see from the code you posted is how those functions are being called.
Anyway, the function responsible for rounding numbers appears to be the first one, format_number(). I'm guessing that somewhere, probably in a different bit of code, that is being called and it is being told to round up to 2 places instead of 3.
Take a look at the last couple of lines in the code below:
What I'd suggest is doing a search for "format_number(" in your IDE and look for code that is asking for 2 decimal places rather than 3.
Anyway, the function responsible for rounding numbers appears to be the first one, format_number(). I'm guessing that somewhere, probably in a different bit of code, that is being called and it is being told to round up to 2 places instead of 3.
Take a look at the last couple of lines in the code below:
Code: Select all
// Your number formatting function ...
function format_number($float, $decimal_places = null, $format_negative = false, $suppress_commas = true, $negative_in_brackets = true)
{
if ($decimal_places === null)
{
$decimal_places = 4; //TODO: Load from config
}
else
{
$decimal_places = intval($decimal_places);
}
// Commented out temporarily
/* if (nbf_globals::$system_locale)
{
@setlocale(LC_ALL, nbf_globals::$system_locale); //You could force this to a different locale here if your system default one is not right
} */
$is_negative = $float < 0;
if ($is_negative)
{
$float = abs($float);
}
$str_float = str_replace(",", ".", $float . ""); //Convert float to string, and if locale indicates a comma decimal separator, replace with dot
if (strpos($str_float, ".") !== false && substr($str_float, strlen($str_float) - 1) == '5')
{
$float += 0.00001;
}
$ret_val = $float;
if ($is_negative)
{
$ret_val = 0 - $ret_val;
}
if ($suppress_commas)
{
$thousands = "";
}
else
{
$thousands = ",";
}
$ret_val = number_format($ret_val, $decimal_places, ".", $thousands);
if ($format_negative)
{
if ($ret_val < 0)
{
if ($negative_in_brackets)
{
$ret_val = "<span style=\"color:#ff0000;\">(" . str_replace("-", "", $ret_val) . ")</span>";
}
else
{
$ret_val = "<span style=\"color:#ff0000;\">$ret_val</span>";
}
}
}
if (!$suppress_commas && $format_negative && function_exists("localeconv")) //Only applied to HTML output (invoices/reports)
{
$locale_info = localeconv();
if (strlen(@$locale_info['mon_thousands_sep']) > 0 && strlen(@$locale_info['mon_thousands_sep']) < 4)
{
$ret_val = str_replace(",", "!!#!!", $ret_val); //In case decimal point becomes comma
}
if (strlen(@$locale_info['mon_decimal_point']) > 0 && strlen(@$locale_info['mon_decimal_point']) < 4)
{
$ret_val = str_replace(".", @$locale_info['mon_decimal_point'], $ret_val);
}
if (strlen(@$locale_info['mon_thousands_sep']) > 0 && strlen(@$locale_info['mon_thousands_sep']) < 4)
{
$ret_val = str_replace("!!#!!", @$locale_info['mon_thousands_sep'], $ret_val);
}
}
//Revert back to default US locale so that database inserts are not messed up by unexpected commas
@setlocale(LC_ALL, "en_US", "en-US", "en", "English_United States", "en_US.UTF-8");
return $ret_val;
}
// I'm using 6.21345 as an example number.
// We pass the number itself first, then the
// number of decimal places:
echo format_number(6.21345, 3);
// Whereas for 2 decimal places we would do:
echo format_number(6.21345, 2);Re: Some help regarding rounding
Thanks mate, looking now
Will reply with answer,
Cheers
Graeme
Will reply with answer,
Cheers
Graeme