0

An example will clear the idea:

number A = 12 number B = 20

I need to divide A per 5 until I dont go less than 5. So I get 3 parts: 5,5 an 2. Now I have to use this result to split B given the weight just calculated. So 20 * (5/12), 20 * (5/12), 20* (2/12) and their sum of course must be exactly equal to B (20 in our case)

I have to do this without losing any precision and trying to have the result as much correct as possible. My example is using int, but I need to do that with decimals as well.(A could be 12.37 and B could be 20.13 for instance) Anyone knows a library or a hint to do that ?

Bhargav Rao
  • 50,140
  • 28
  • 121
  • 140
dr_85
  • 61
  • 8
  • So just to get this right (the example is rather confusing - e.g. what does "divide A per 5 until I don't go less than 5" mean?): you want a sequence of numbers `(a1, a2, ..., an)`, such that all elements are `<= 5` and `a1 / A * B + a2 / A * B + ... + an / A * B = B` and `a1 + a2 + ... + an = A`? In addition: does the sequence only contain integers, or are doubles valid as well? –  Jan 13 '17 at 16:07
  • Have you looked at java BigDecimal and BigInteger? – mba12 Jan 13 '17 at 16:09
  • Sorry guys, you are right, the description is bad. When I say that I need to divide by 5, it means until I can do it with % equals to 0. So if A is 16 --> 5,5,5,1 if A is 6 I get 5 and 1, if A is 13 I get 5,5 and 3. The sequence can contains double. It is fine. But we need to pay attention as working with decimals is risky. – dr_85 Jan 13 '17 at 16:12

3 Answers3

1

Well, this question (at least the way I understand it) is pretty simple to solve:

What we've got: A and B, which may be decimal
What we want: a sequence (a1, a2, ..., an) with the following properties:

  • any element of the sequence is smaller equal 5
  • all elements sum up to A: a1 + a2 + ... + an = A
  • a1 / A * B + a2 / A * B + ... + an / A * B = B

Well time for a bit of math:

B = //RHS => LHS
a1 / A * B + a2 / A * B + ... + an / A * B = //factorize
(a1 + a2 + ... + an) / A * B =  //(a1 + a2 + ... + an) = A
B

Or in other words: use whatever sequence you like. As long as the elements of the sequence sum up to A and are all smaller-equal to B you're fine.

As for the precision:
Using the type of the input there shouldn't be any issue with precision, as the output can be built in a manner to only consist of integers and the decimal part of the input (so actually your output might have a better -unused - precision than the input).

So to generate the values a1 / A * B, a2 / A * B, ... we need to do the following:
Use BigDecimal for maximum-precision - beware though, as B / A may be periodic! The rest works just the usual way, except that you need to use methods instead of normal operators:

  • a + b with BigDecimal would be a.add(b)
  • a * b with BigDecimal would be a.multiply(b)
  • ...

You can look up the details in the documentation.

  • Thanks for your reply Paul. I need exactly these values : 20 * (5/12), 20 * (5/12), 20* (2/12) , so with your algorith how I can get them ? – dr_85 Jan 13 '17 at 16:39
  • @darkRevan85 You mean you want the values created by multiplying elements of the sequence with `A / B`? Well, the main-problem, which I've already shown in my answer is that there is no distinct way of splitting `A` up. In fact there's an infinite number of ways. E.g.: for `A = 10`, you could use the sequence `(5, 5)`, or `(5, 5, 5, 5, 5, -15)` or `(3.33, 3.33, 3.33)`. So you'll first have to decide how you'll get that sequence in a distinct way. –  Jan 13 '17 at 16:43
  • The sequence must be like I said. I must divide by 5. Only the sequence (5,5) is correct in your example. If I had 11.77, the sequence must be 5,5,1.77 – dr_85 Jan 13 '17 at 16:48
  • Yep, BigDecimal are good for that, I wonder if there is an easy way to use long to avoid bad performances. – dr_85 Jan 13 '17 at 17:03
  • @darkRevan85 not really. Of course you could use `long` to represent a [fixed-point-decimal](https://en.wikipedia.org/wiki/Fixed-point_arithmetic). But this comes with a few limitations, both in terms of maximum representable decimal places and precision. [This question](https://stackoverflow.com/questions/11916308/fixed-point-arithmetics-in-java-with-fast-performance) covers that topic in detail. –  Jan 13 '17 at 17:32
0

after reading your question, i cant figure out what is that you want. Do you want the sequence of 5,5,5,..n(where n<5) for A or B,and also the thing about sum for B is it a condition or is that what you are trying to achieve ?

anyway if its the sequence that you want then you could do this :

int A,B;            //if A=12
int numOfFives=A/5; // then numOfFives=2
int remainder=A%5;  //then remainder=2

using this method will ensure that the last number will always be less than one.

so you could do the sum like :

sum=0;
for(int i=0;i<numOfFives;i++){
sum+=B*(5d/12d); // 5/12 with sum as int gives result sum =0 , so change the fraction part accordingly to your need. 
}
sum+=B*(remainder/12d);

if you want the sequence then do :

System.out.println("Sequence = ");
for(int i=0;i<numOfFives;i++){
System.out.println(5+",");
}
System.out.println(remainder);

also make your calulation of sequence much easier.

Edit 1

here is the Live Program on IdeOne if you want to check it out.

inputs :
A=12
B=20

outputs:
Final Sum=20.0
Sequence=5,5,2
anotherGatsby
  • 1,568
  • 10
  • 21
  • Thanks for your reply. That is good but I need to support decimals numbers. (both A and B) – dr_85 Jan 13 '17 at 22:48
  • the `5d/12d` gives an answer in double which has decimals places upto 15 digits you want more ? for decimal support all you have to do is initialize `A`,`B`,`sum` with the type `double` – anotherGatsby Jan 14 '17 at 03:43
0

Try out this example:

import java.math.BigDecimal;
import java.math.RoundingMode;

public class Example {

    public static void main (String[]args) { 
        BigDecimal a = new BigDecimal("16.3");    
        BigDecimal b = new BigDecimal("20");
        BigDecimal[] div_rem = a.divideAndRemainder(new BigDecimal("5"));
        String s = "";
        for (int i = 0; i<div_rem[0].intValue();i++){
           s += b +" * (5/"+a+"), ";
        }
        s += b +" * ("+div_rem[1]+"/"+a+")";
        System.out.println(s);

        System.out.println(b +" * (5/"+a+") = " + b.multiply(new BigDecimal("5").divide(a, 5,RoundingMode.HALF_UP)));
        System.out.println(b +" * ("+div_rem[1]+"/"+a+") = " + b.multiply(div_rem[1].divide(a,5 ,RoundingMode.HALF_UP)));
    }            
}
Eritrean
  • 15,851
  • 3
  • 22
  • 28