How can I make sure that a rounding error doesn't happen when I multiply a number, round it, then pull it back out?

How can I make sure that a rounding error doesn't happen when I multiply a number, round it, then pull it back out?

rounding error example
rounding error footnote
floating point rounding error
round off error and truncation error
how to minimize round-off error
round off error python
round off error java
round off error c++

We have this API that we need to make payments to. On our side we have an initial payment and a fee of 3% that we add to get the total. We take this and pass it to the API which then pulls it apart. It knows about the 3% fee and breaks it down to the fee and the payment by takeing the total amount and multipling by 97.09% to get the payment. The problem we are having is that the API only excepts to 2 decimals places but we need things to work out to the penny. So for example:

payment: $100.01
makes fee of $3.0103
total = payment + fee = 103.0103 (rounded to 103.01)
reverseEngineered = total * percent = 103.01 * .9709
leaves us with 100.012409 (100.01) 

Which is correct but for this example

payment = $333.33
makes fee of 9.9999
total = payment + fee = 343.3299 (rounded to 343.33)
reverseEngineered = total * percent = 343.33 * .9709
leaves us with 333.339097 (333.34) 
333.33 != 333.34 so there is a problem when rounding.

I don't control the API otherwise I would have the percent be more accurate (97.08737864%).

Any ideas on how this can be done or is there no way to ensure it returns witout rounding errors.

After doing some math i found that using %2.99721907 as the fee percentage make more numbers work out

{
    Though process x*y = z therefor z / y = x;
    x / .9709 = z therefor z *  .9709 = x
    1 / .9709 = 1.299721907
}

Example

payment = $333.33
makes fee of 9.9906303260
total = payment + fee = 343.3206 (rounded to 343.32)
reverseEngineered = total * percent = 343.32 * .9709
leaves us with 333.329388 (333.33) 

But I'm not sure this will always be the case. Does anyone know a way I could be sure? Or will this not work for every number?

Edit:

I'm going to be more clear about the standing with the API. We didn't write/ don't have control over the API. A company we are working with do. We might be able to suggest changes but nothing more that that.

When we send the payment over the API on the other companies end they are breaking the payment and fee apart and sending the funds to two separate accounts. This is why the fee needs to be reverse engineered


Since 97.08737864 does not equal 97.09, you're screwed. Why are you using an API for such a simple calculation?

What is rounding error?, When writing your own, be sure to unit test it and make sure you are doing the math correctly. that should give the same result, they often don't because of rounding errors. And note that it doesn't matter how much precision you have. The unexpected result led Lorenz to a powerful insight into the way nature works: small changes can have large consequences. The idea came to be known as the “butterfly effect” after Lorenz


Well, as I think you know by now, it will never work-you need to change the api. You can't redefine math.

Set rounding precision - Excel - Office Support, Explanation of the reasons for rounding errors in floating-point math, and of rounding rounding, and neither does 10000 or 1110 - but 1001 will have to be rounded. after a certain point, and this can already happen for very simple fractions. Also I am a bit confused when you say you can not add anything to the values when I mentioned but if you use modulus you can then round up? Isn't rounding up adding to the value like I did? Also you could just call the function when outputting and it doesn't modify the value since not passing by reference.


Since you have the original payment and you know the processing fee, why are you reprocessing their number?

Do your own more accurate calculation and return it to the customer? (if that's where it's going) And suck up the cost of any rounding errors in the processor's favour (or yours).

It'd be nice to put a disclaimer in your ToS that due to the processor you're using, rounding is only accurate to 2 decimal places, yadda yadda.

Understanding Floating Point Precision, aka “Why does Excel Give , I'd also use a non-linear divisor to get the relative error - it doesn't seem right that For the number of percentages that need to be rounded up, take an item from Not sure if this would work in general, but it seems to work similar if the order is  A roundoff error, also called rounding error, is the difference between the result produced by a given algorithm using exact arithmetic and the result produced by the same algorithm using finite-precision, rounded arithmetic. Rounding errors are due to inexactness in the representation of real numbers and the arithmetic operations done with


I was testing this out in php/Laravel. Dumping the starting payment and the final result to the log files along with the overall difference between the original payment and the final result payment. This is the code I used for testing.

<?php

namespace App\Http\Controllers;

use App\Project;
class ProjectsController extends Controller
{

    public function run(){
        set_time_limit(300000);
        for ($payment = 330; $payment < 340; $payment += .01) {
            //Fix the weird increment problem with floats
            $payment = round($payment,2);
            $fee = $this->applyFee($payment);
            $total = $fee + $payment;
            $returned = $this->passToAPI($total,true,false);
            // \Log::alert($payment . ": " . ($returned["Payment"] - $payment));
            \Log::alert($payment .": " . round($returned["Payment"],2));
            \Log::alert($payment - $returned["Payment"]);

            if($payment != round($returned["Payment"],2)){
                \Log::alert($payment . " is unequal");
            }
        }
    }

    public function passToAPI($value, $round = true, $roundResult = true){
        $rndTotal = $round ? round($value,2) : $value;
        $Payment = $this->reverseEngineerPayment($rndTotal); 
        $Fee = $rndTotal - $Payment;
        $Payment = $roundResult ? round($Payment,2) : $Payment;
        $Fee = $roundResult ? round($Fee,2) : $Fee;
        return  array("Payment" => $Payment, "Fee" => $Fee);
    }

    public function reverseEngineerPayment($total){
        return $total * .9709;
    }
    public function applyFee($payment){
        return $payment * .0299721907;
    }

    public function reverseEngineerFee($total){
        return $total * .0291;
    }
}

When using .03 for the applyFee function the results were somthing like this

[2018-07-12 13:47:10] local.ALERT: 330: 330.01  
[2018-07-12 13:47:10] local.ALERT: -0.0089099999999576  
[2018-07-12 13:47:10] local.ALERT: 330 is unequal  
[2018-07-12 13:47:10] local.ALERT: 330.01: 330.02  
[2018-07-12 13:47:10] local.ALERT: -0.0086190000000101  
[2018-07-12 13:47:10] local.ALERT: 330.01 is unequal
[2018-07-12 13:47:10] local.ALERT: 330.02: 330.03  
[2018-07-12 13:47:10] local.ALERT: -0.0083280000000059  
[2018-07-12 13:47:10] local.ALERT: 330.02 is unequal  
[2018-07-12 13:47:10] local.ALERT: 330.03: 330.04  
[2018-07-12 13:47:10] local.ALERT: -0.0080370000000016  
[2018-07-12 13:47:10] local.ALERT: 330.03 is unequal  
[2018-07-12 13:47:10] local.ALERT: 330.04: 330.05  
[2018-07-12 13:47:10] local.ALERT: -0.0077459999999974  
[2018-07-12 13:47:10] local.ALERT: 330.04 is unequal
...

Which was kind of expected because of the calculation rounding error.

But when I used .0299721907 for the applyFee function the results were like this

[2018-07-12 13:50:21] local.ALERT: 330: 330  
[2018-07-12 13:50:21] local.ALERT: 0.00079900000002908  
[2018-07-12 13:50:21] local.ALERT: 330.01: 330.01  
[2018-07-12 13:50:21] local.ALERT: 0.0010900000000333  
[2018-07-12 13:50:21] local.ALERT: 330.02: 330.02  
[2018-07-12 13:50:21] local.ALERT: 0.0013809999999808  
[2018-07-12 13:50:21] local.ALERT: 330.03: 330.03  
[2018-07-12 13:50:21] local.ALERT: 0.001671999999985  
[2018-07-12 13:50:21] local.ALERT: 330.04: 330.04  
[2018-07-12 13:50:21] local.ALERT: 0.0019630000000461  
[2018-07-12 13:50:21] local.ALERT: 330.05: 330.05

They always returned to the penny the result I passed in. It seems like the rounding error only goes up the the decimal after the penny making it so the results are always the desired results. Note* I also tested this script from 1 to 50,000. and was unable to find any instances where the result wasn't the same.

I realize this is pretty clunky but it works as far as I can tell. If you can find a reason that this wouldn't work out then I'll be happy to not use it, but as far as I can tell it's solid.

Solutions for floating point rounding errors, A rounding error can be especially problematic when rounded input is used in a series of calculations, causing the error to compound, and  Any ideas on how this can be done or is there no way to ensure it returns witout rounding errors. After doing some math i found that using %2.99721907 as the fee percentage make more numbers work out { Though process x*y = z therefor z / y = x; x / .9709 = z therefor z * .9709 = x 1 / .9709 = 1.299721907 } Example


Rounding Errors, You can frequently prevent floating point rounding errors from affecting your work by setting the This option forces the value of each number in the worksheet to be at the Use this option only if you are certain that the displayed precision will​  Excel doesn't do that; it uses the obsolete theory that always rounds up so 2.5, which should round to 2, is being rounded to 3. This means that over time, in financial uses, money will eventually be over-reported, and in scientific uses, the amount of energy and matter will eventually be over-reported.


How to make rounded percentages add up to 100%, In certain types of computation, roundoff error can be magnified as any initial errors are carried through one or more intermediate steps. An egregious example​  20.1.1 Rounding parameters Like the Excel functions, the think-cell rounding functions take two parameters: x The value that is to be rounded. This can be a constant, a formula or a reference to another cell. n The rounding precision. The meaning of this parameter depends on the function you use.


Rounding Error Definition, When an executive sees a calculation error on your slide, how does it technique to make sure you eliminate the rounding errors that often  I knocked it back to 2400MHz (even though 2450MHz was stable through all testing except Prime95) and am running it at the second highest voltage offered (1.5375 IIRC) to see if it can pass Prime95. I will also try Auto voltage again after this if this errors out. I will also try Memtest86+ again to make sure it's not a memory issue.