rolandmy asked on # Mathematical Formulae

Dear experts,

I had this function in PHP provided by an expert previously.

Usage is roundToNickle(number_format($variable, 2, '.', ''))

The result I got for say, 0.186666666667 is 0.2 which is not wrong for billing purpose. However, to calculate the actual cost, I need the result to be 0.19

Other results

0.213333333333 gives me 0.2 when I need it to be 0.22

0.0533333333333 gives me 0.5 when I need it to be 0.06

Any chance for experts to update the function?

I had this function in PHP provided by an expert previously.

```
function roundToNickle($value) {
// multiply the value by 100
// for some reason value%.05 gives a divide by zero error
$value *= 100;
// get remainder of value / 5
$remain = $value % 5;
if ($remain < 2.5) {
// round down by subtracting the remainder
$value -= $remain;
} else {
// round up by adding difference between 5 and remainder
$value += (5-$remain);
}
// round it off just to be safe
$value = round($value);
// divide by 100 to get back to a decimal amount
$value /= 100;
return $value;
}
```

Usage is roundToNickle(number_forma

The result I got for say, 0.186666666667 is 0.2 which is not wrong for billing purpose. However, to calculate the actual cost, I need the result to be 0.19

Other results

0.213333333333 gives me 0.2 when I need it to be 0.22

0.0533333333333 gives me 0.5 when I need it to be 0.06

Any chance for experts to update the function?

PHPAlgorithmsProgramming Theory

Log in or sign up to see answer

Become an EE member today7-DAY FREE TRIAL

Members can start a 7-Day Free trial then enjoy unlimited access to the platform

or

Learn why we charge membership fees

We get it - no one likes a content blocker. Take one extra minute and find out why we block content.

Not exactly the question you had in mind?

Sign up for an EE membership and get your own personalized solution. With an EE membership, you can ask unlimited troubleshooting, research, or opinion questions.

ask a questionLog in or sign up to see answer

Become an EE member today7-DAY FREE TRIAL

Members can start a 7-Day Free trial then enjoy unlimited access to the platform

or

Learn why we charge membership fees

We get it - no one likes a content blocker. Take one extra minute and find out why we block content.

Not exactly the question you had in mind?

Sign up for an EE membership and get your own personalized solution. With an EE membership, you can ask unlimited troubleshooting, research, or opinion questions.

ask a questionozo

or just round($value,2)

Get an unlimited membership to EE for less than $4 a week.

Unlimited question asking, solutions, articles and more.

rolandmy

You guys are almost there.

0.213333333333 gives me 0.21

I wanted 0.22 as the result.

Even if the value is 0.01123, I need the result to be 0.02 after applying the function or round.

0.213333333333 gives me 0.21

I wanted 0.22 as the result.

Even if the value is 0.01123, I need the result to be 0.02 after applying the function or round.

ozo

If you want to round up, use ceil instead of round

All of life is about relationships, and EE has made a viirtual community a real community. It lifts everyone's boat

William Peck

Cornelia Yoder

I don't think ceil() will work because that result is always an integer.

ozo

ceil($value*100)/100

instead of

round($value*100)/100

instead of

round($value*100)/100

Cornelia Yoder

You can always round up this way using ceil()

$out = ceil(($value*100))/100;

$out = ceil(($value*100))/100;

Get an unlimited membership to EE for less than $4 a week.

Unlimited question asking, solutions, articles and more.

ozo

But note that 0.01 is not represented exactly in IEEE Standard 754 Floating-Point

so when you think you are passing it 0.07 you may really be passing it

0.070000000000000006661338147751

so when you think you are passing it 0.07 you may really be passing it

0.070000000000000006661338

rolandmy

ceil(($value*100))/100; works to a certain extend.

Results:

0.0533333333333 gives me 0.06, which is what I wanted.

The problem is with other results generated, 0.72 gives me 0.73 and 0.24 gives me 0.25. These should stay at 0.72 or 0.24.

The other noticeable ones are 0.48 becomes 0.49, 0.56 becomes 0.57. Seem to be happening to results with 2 decimal places.

Some results are correct though, like 0.08 stays at 0.08

Results:

0.0533333333333 gives me 0.06, which is what I wanted.

The problem is with other results generated, 0.72 gives me 0.73 and 0.24 gives me 0.25. These should stay at 0.72 or 0.24.

The other noticeable ones are 0.48 becomes 0.49, 0.56 becomes 0.57. Seem to be happening to results with 2 decimal places.

Some results are correct though, like 0.08 stays at 0.08

ozo

In IEEE Standard 754 single precision Floating-Point the closest representable value to 0.72 is

.7200000286102294921875

If you need exact values, you should not be using floating point.

Can you work in pennies instead of pounds or dollars and use integers?

.7200000286102294921875

If you need exact values, you should not be using floating point.

Can you work in pennies instead of pounds or dollars and use integers?

Your help has saved me hundreds of hours of internet surfing.

fblack61

Get an unlimited membership to EE for less than $4 a week.

Unlimited question asking, solutions, articles and more.

ozo

If you can guarantee, for example, that you will never need to distinguish between

0.72 and 0.720001

then you may be able to manage with something like

round($value*100+0.499999)/100

But that will also fail at some point.

For example, if you use single precision IEEE Standard 754 Floating-Point,

10000.720002 will be indistinguishable from 10000.72

If you know what you can guarantee in terms of how close a number can be without rounding up, and what the range of numbers you need to be able to handle, and the precision of the floating point numbers you are using, we may be able to suggest an appropriate threshold, but remember

“Floating point computation is by nature inexact, and programmers can easily misuse it so that the computed answers consist almost entirely of “noise.” One of the

principal problems of numerical analysis is to determine how accurate the results of

certain numerical methods will be. There is a “credibility-gap”: We don’t know how

much of the computer’s answers to believe. Novice computer users solve this problem

by implicitly trusting in the computer as an infallible authority; they tend to believe

that all digits of a printed answer are signi¿cant. Disillusioned computer users have

just the opposite approach; they are constantly afraid that their answers are almost

meaningless.”

See also

https://www.validlab.com/goldberg/paper.pdf

0.72 and 0.720001

then you may be able to manage with something like

round($value*100+0.499999)

But that will also fail at some point.

For example, if you use single precision IEEE Standard 754 Floating-Point,

10000.720002 will be indistinguishable from 10000.72

If you know what you can guarantee in terms of how close a number can be without rounding up, and what the range of numbers you need to be able to handle, and the precision of the floating point numbers you are using, we may be able to suggest an appropriate threshold, but remember

“Floating point computation is by nature inexact, and programmers can easily misuse it so that the computed answers consist almost entirely of “noise.” One of the

principal problems of numerical analysis is to determine how accurate the results of

certain numerical methods will be. There is a “credibility-gap”: We don’t know how

much of the computer’s answers to believe. Novice computer users solve this problem

by implicitly trusting in the computer as an infallible authority; they tend to believe

that all digits of a printed answer are signi¿cant. Disillusioned computer users have

just the opposite approach; they are constantly afraid that their answers are almost

meaningless.”

See also

https://www.validlab.com/goldberg/paper.pdf

Cornelia Yoder

There are mathematical ways to fix this floating point problem, but ozo is absolutely correct that it is inherent in the use of floating point data.

You would need to decide at which decimal point you want to discard the rest.

If you round up .720034, then should you round up .72000000000000034? How many zeroes are enough before you decide it is .72 rather than .73?

You would need to decide at which decimal point you want to discard the rest.

If you round up .720034, then should you round up .72000000000000034? How many zeroes are enough before you decide it is .72 rather than .73?

Ray Paseur

Notes about using float values in PHP (see the large red warning box):

http://php.net/manual/en/language.types.float.php

If you would like to get a tested and working code sample, please follow the guidance of the SSCCE. In this case, if you can give us a list of the*input* values and the desired *output* values, we can show you the exact code to get from input to output. Obviously the quality of the test data matters, so please feel free to throw in not only the mainstream, but also the edge cases when you make your list.

http://php.net/manual/en/language.types.float.php

If you would like to get a tested and working code sample, please follow the guidance of the SSCCE. In this case, if you can give us a list of the

Get an unlimited membership to EE for less than $4 a week.

Unlimited question asking, solutions, articles and more.

rolandmy

Erm. Refer to the list below for sample "live" values that I extracted from the database.

0.186666666667 becomes 0.19 <-- correct

0.08 becomes 0.08 <-- correct

0.106666666667 becomes 0.11 <-- correct

0.24 becomes 0.25 <-- wrong (should stay the same value)

0.48 becomes 0.49 <-- wrong (should stay the same value)

0.32 becomes 0.32 <-- correct

0.186666666667 becomes 0.19 <-- correct

0.08 becomes 0.08 <-- correct

0.106666666667 becomes 0.11 <-- correct

0.24 becomes 0.25 <-- wrong (should stay the same value)

0.48 becomes 0.49 <-- wrong (should stay the same value)

0.32 becomes 0.32 <-- correct

Cornelia Yoder

In your database, what is the data type of the values?

float?

double?

decimal?

What precision is specified for it?

float?

double?

decimal?

What precision is specified for it?

Get an unlimited membership to EE for less than $4 a week.

Unlimited question asking, solutions, articles and more.

rolandmy

Ray, you will forever remain as the hero of ee.

Now it goes back to my original problem (the main question).

As I mentioned in the question, I need to round up.

Data like 1.011 becomes 1.01. I need it to be 1.02

Or data like 0.21333 becomes 0.21 instead of 0.22

P.s. The roundtoNickle function was from an expert here. It suited my needs back then.

Now it goes back to my original problem (the main question).

As I mentioned in the question, I need to round up.

Data like 1.011 becomes 1.01. I need it to be 1.02

Or data like 0.21333 becomes 0.21 instead of 0.22

P.s. The roundtoNickle function was from an expert here. It suited my needs back then.

I started with Experts Exchange in 2004 and it's been a mainstay of my professional computing life since. It helped me launch a career as a programmer / Oracle data analyst

William Peck

ozo

"Data like 1.011 becomes 1.01. I need it to be 1.02"

Should 1.0101 become 1.02?

Should 1.01001 become 1.02?

Should 1.010001 become 1.02?

At some point, if your numbers are represented as floats, there may be a problem defining where you draw the line between 1.01 and 1.02

Depending on how precisely you want to draw that line there may be trade offs we can make to do it with floats, or it may be impossible to do using floats.

for the particular values in your list:

round($value+.0049,2) may suffice, but there will be other values it will fail on, so unless there are values for which failure is acceptable (perhaps because you can guarantee that you will never see those values) we cannot guarantee a function that works in all cases.

Are you sure you can't work with integer penny values instead of float pound/dollar values?

Should 1.0101 become 1.02?

Should 1.01001 become 1.02?

Should 1.010001 become 1.02?

At some point, if your numbers are represented as floats, there may be a problem defining where you draw the line between 1.01 and 1.02

Depending on how precisely you want to draw that line there may be trade offs we can make to do it with floats, or it may be impossible to do using floats.

for the particular values in your list:

0.186666666667 becomes 0.19 <-- correctSomething like

0.08 becomes 0.08 <-- correct

0.106666666667 becomes 0.11 <-- correct

0.24 becomes 0.25 <-- wrong (should stay the same value)

0.48 becomes 0.49 <-- wrong (should stay the same value)

0.32 becomes 0.32 <-- correct

round($value+.0049,2) may suffice, but there will be other values it will fail on, so unless there are values for which failure is acceptable (perhaps because you can guarantee that you will never see those values) we cannot guarantee a function that works in all cases.

Are you sure you can't work with integer penny values instead of float pound/dollar values?

Ray Paseur

my original problem (the main question).To help you any further we need to see the SSCCE. In this case that would be a set of input values and the expected outputs, along with the rules you want to apply to transform the inputs into the outputs. A two column layout of the inputs and the corresponding expected outputs would suffice. Please post that here, and I'll try to help you make sense of it.

However, please note that there are laws about handling money values, so if your rules violate the laws, you may expect a knock at the door.

rolandmy

Sorry for late reply. Long holiday over here. Going to accept multiple solutions.

Get an unlimited membership to EE for less than $4 a week.

Unlimited question asking, solutions, articles and more.