I am trying to solve this problem:
When I purchase items I receive a receipt which lists the name of all
the items and their price (including tax), finishing with the total
cost of the items, and the total amounts of sales taxes paid. The
rounding rules for sales tax are that for a tax rate of n%, a shelf
price of p contains (np/100 rounded up to the nearest 0.05) amount of
sales tax.
So, ... I have a price in php:
$value = 11.25;
and I don't understand why
var_export(ceil($value * 0.05 * 10));
returns 6 and dividing per 10, the result is
var_export(ceil($value * 0.05 * 10) / 10);
0.59999999999999998
some nice experiments:
php > echo bcmul(11.25, 0.05, 3);
0.562
php > echo bcmul(ceil(11.25), 0.05, 3);
0.60
You could read what bishop point out and also you could read this in order to understand what is the problem.
Now talking about a solution, you could use PHP BCMath extension which should be used when you want to work with precision mathematical numbers
For arbitrary precision mathematics PHP offers the Binary Calculator
which supports numbers of any size and precision, represented as
strings.
One solution (a ugly one) could be this
$value = 11.25;
var_export(bcdiv(ceil($value * 0.05 * 10), 10, 1)); // Output '0.6'
Here I am using the bcdiv from the mentioned extension.
Related
i'm hoping someone can help with my question.
Let's say I have a quantity which is simply an integer in a variable. I know that if the quantity is below 10, the cost will be 1.50. Between 10-20 the cost would be 1.50 x 2, then between 20-30 the cost would be 1.50 x 3 and so on.
The bit im stuck on is the "and so on". I know how I could code this if I knew there was a limit of let's say 100, however if it can be limitless, how could I code this in an intelligent way to work it out for me?
Sorry for the example-less question. I wouldn't know where to start with this query.
Thank you for your time
Since your steps are in tenfold, you can simply divide your number by 10 to get the amount of 1.5's you'll need to calculate the cost.
Then, we'll use ceil() to round the divison to the next integer. Now, for example, 5/10 = 0,5 results in return 1.5 * 1;
Take a look at this example;
<?php
function getCost($n) {
return 1.5 * ceil($n / 10);
}
var_dump(getCost(5)); float(1.5)
var_dump(getCost(15)); float(3)
var_dump(getCost(25)); float(4.5)
var_dump(getCost(35)); float(6)
var_dump(getCost(100)); float(15)
var_dump(getCost(12345)); float(1852.5)
Try it online!
I am using the moneyphp/money class to store monetary values. However when calculating the tax owed I have an issue where the calculated tax is a decimal and the library is looking for an integerish value.
Example:
$invoiceTotal = new Money("155" new Currency("USD")); //$1.55
$taxRate= 0.065;
$invoiceTotalWithTax = $invoiceTotal->multiply($taxRate);
echo $invoiceTotalWithTax; //0.10 whereas actual value is 1.55*0.065 = 0.10075
$formatter = new DecimalMoneyFormatter();
$formatter->format($invoiceTotalWithTax); //will return $0.10
From the above example, some fractional cent value is being lost. Individually it's not a lot, however if we process several thousand invoice in a tax period, the total tax collected will eventually surpass 1 cent.
Is there a way to handle these situations with the Money package?
If not, then is there another package that can handle this?
Shameless plug: I don't know if there's a way to do it with the moneyphp/money library, but here's how you can handle this situation with the brick/money library (disclaimer: I authored it).
The option you choose will depend on what you're trying to achieve.
Option 1: use a Money with the default scale, round up or down
Use this method if you need the result in the default scale for the currency (2 decimal places for USD), and know which rounding to apply:
use Brick\Money\Money;
use Brick\Math\RoundingMode;
$invoiceTotal = Money::ofMinor('155', 'USD'); // USD 1.55
// or
$invoiceTotal = Money::of('1.55', 'USD');
$taxRate = '0.065'; // prefer strings over floats!
$totalWithTax = $invoiceTotal->multipliedBy($taxRate, RoundingMode::DOWN); // USD 0.10
$totalWithTax = $invoiceTotal->multipliedBy($taxRate, RoundingMode::UP); // USD 0.11
You have many more rounding modes to choose from. If you don't provide a rounding mode, and the result does not fit into 2 decimal places, you'll get an exception.
Option 2: use a Money with a custom scale
If you need to work with a given precision, say 5 decimal places, you can specify this when you create the Money:
use Brick\Money\Money;
use Brick\Money\Context\CustomContext;
use Brick\Math\RoundingMode;
$invoiceTotal = Money::of('1.55', 'USD', new CustomContext(5)); // USD 1.55000
$taxRate = '0.065';
$totalWithTax = $invoiceTotal->multipliedBy($taxRate); // USD 0.10075
If the result does not fit into 5 decimal places, you'll need to provide a RoundingMode, or you'll get an exception.
Option 3: use a Money with auto scale
Use this method to automatically adjust the scale of the result to the correct number of decimal places:
use Brick\Money\Money;
use Brick\Money\Context\AutoContext;
use Brick\Math\RoundingMode;
$invoiceTotal = Money::of('1.55', 'USD', new AutoContext()); // USD 1.55
$taxRate = '0.065';
$totalWithTax = $invoiceTotal->multipliedBy($taxRate); // USD 0.10075
No rounding mode is involved, but if a division yields a decimal number with an infinite number of digits, you'll get an exception.
Option 4: use a RationalMoney
A RationalMoney is a money object that represents its amount as a rational number (a fraction). It's particularly useful when you need to chain several operations with no rounding whatsoever:
use Brick\Money\Money;
use Brick\Math\RoundingMode;
$amount = Money::of('1.55', 'USD'); // USD 1.55
$amount = $amount->toRational(); // USD 155/100
$amount = $amount->dividedBy(3); // USD 155/300
$amount = $amount->dividedBy(7); // USD 155/2100
Once you have performed all your operations, you can convert your final number to a decimal Money, using a rounding mode if necessary:
use Brick\Money\Context\DefaultContext;
use Brick\Money\Context\CustomContext;
$amount->to(new DefaultContext(), RoundingMode::DOWN); // USD 0.07
$amount->to(new CustomContext(6), RoundingMode::DOWN); // USD 0.073809
Final considerations
The brick/money package offers formatting, cash roundings, money allocation, currency conversion, and more. It is based on the brick/math package, that performs calculations on numbers of any scale. Give it a try!
Hey guy's I am working on a project of mine which involves the use of money. I am trying to not use round anymore because, it's rounding things to nearest tenth and I need exact numbers. One reason I was using it, was because it was giving a whole number.
The way I am working my number system is that 100 = $1, 2000 = $20, etc.. I was currently using the round function because it would get rid of the decimal point for me and give me a whole number, lets say: 223 which in turn would = $2.23.
Here is what I am using:
$amount += round(($amount / 29) + 30);
Here are the numbers:
Lets say we have a charge of 100 and we add 125 which equal 225 (USD $2.25). Now we add taxes and processing: + 2.9% + $.30. After multiplying 2.25 by 2.9% and adding .30 the amount would be: 0.36525 - this is the amount that should be added than to the $2.25 which than would be 261 = $2.61
The issue is because of the rounding, when I look in my Stripe panel (I am using Stripe API for payments) I see a charge of $2.63. So my question is, how would I go about making it exact without having any rounding and decimal places.
UPDATE:
Here is the above example more explained:
Lets say we have a charge of 100 and we add 125 which equal 225 (USD $2.25). Now we add taxes and processing: + 2.9% + $.30. After multiplying 2.25 by 2.9% and adding .30 the amount would be: 0.36525 - this is the amount that should be added than to the $2.25 which than would be 261 = $2.61
So now with that the actual value of amount that should be charged is $2.61 but instead when using the round it gives me 263 which also means $2.63. The above example is the simple math that is correct.
In order to avoid calculation hiccups like that, only round the final result. Keep all other calculations as accurate as possible:
$original = 100;
$original += 125;
$tax = $original * 2.9 / 100; //+2.9%
$tax += 30; //+$.30
$original += $tax; //Add tax.
echo $original; //Result is 261.525. Round as you please.
You can specify precision and rounding method to keep it consistent (PHP round()), then you can deal with the actual values. Doing math tricks like multiplication by a multiple of 10 will only make it more confusing in the long run.
$amount += round(($amount / 29) + 30, 2, PHP_ROUND_HALF_UP);
Will this solve your problem?
Currently I'm using a uniform distribution to generate a winning probability.
For a probability of let's say 1% I define a winning number 47 then I do a mt_rand(1,100) and if the number is 47 the user win. Which is fine.
This work well for small probability like 1/100'000 but when I want a probability of let's say 40% which is 1/0.4 = 2.5
I cannot make mt_rand(1,2.5) I have to do mt_rand(1,2) or mt_rand(1,3) which mean respectively 50% and 33%.
How should I do to get a 40% probability?
let's say you want winning probability as x (assuming an integer), then generate
$num = mt_rand (1,100)
if ($num<=$prob) {//user wins}
If you don't have $prob as an integer and is a number with 2 decimal places eg: 47.23%, then you could generate
$num = mt_rand(1,10000)
if ($num/100 <= $prob), {//user wins}
Similarly you can extend it to whatever accuracy you want
if (mt_rand(1, 100) / $probability <= 1) {
// success
}
E.g. if you have now $probability = 10; you have ten (of hundred) cases where the number between 1 and 100 is smaller or equal to one.
I'm modifying one of OpenCart's product filters to filter products in/out by price. What I do is get all products belonging to a certain category and extract their prices to put them in a slider, but this is not elegant or 'professional' at all, and I would like to code a proper solution.
Let's say I have the following prices: 125, 270, 517, 1680 and 14790. What I would like to do (ideally) is get the highest number (14790 in this short example) and, from it, get something like '15000', so I can divide that between a given factor (like 100) and put that into a slider.
Is there a PHP function to do this kind of calculation?
If I understand your question, and you're asking to round to essentially the nearest 100, there isn't a specific function, but with a bit of maths you can round to the nearest hundred like so:
$price = ceil($price / 100) * 100;
Using:
$price = ceil($price / 1000) * 1000;
Would round to the nearest 1000.
Get the max number, then round it up to the nearest thousand?
<?php
$largest = max(125, 270, 517, 1680, 14790);
$nearest = ceil($largest / 1000) * 1000;
You could just loop through the numbers, remembering the highest value as you go. It's common coding practice. (Ok there really is a max() function as well, echo max(1, 3, 5, 6, 7); // 7)
Then you could divide the highest number by your factor, take the integer you get and add one to it, then multiply by the factor again and there you go.
just do : x=floor(14790/100) ; the floor function returns the next lowest integer value