1

As an extension to my answer to this question, I am trying to split a real number in such a way that each of the two numbers differ by atmost 1 in their last digit (subject to the limitations of floating point arithmetic representation).

For example:

7     => 4, 3
7.2   => 3.6, 3.6
7.3   => 3.7, 3.6 (or 3.5999999999999996) -- I understand this is a corner case and it is alright
7.25  => 3.63, 3.62
7.225 => 3.613, 3.612

To clarify, the resultant addends must contain the same number of digits as the original number.

This is what I've come up with so far.

var x = 7.3;

if(x != Math.round(x)) {
    var p1 = Math.ceil((x  / 2) * 10) / 10;
} else {
    var p1 = Math.ceil(x  / 2);
}
var p2 = x - p1;

console.log(p1, p2);

This works for whole numbers and numbers with one decimal after the point as of now. I believe the general solution would involve figuring out how many digits appear after the point.

I am unsure of how to do this, but I believe one solution would involve converting to a string, splitting on '.', finding the digit count, and then multiplying/dividing by the appropriate power of 10... basically extending the code I've written, so it works for any arbitrary number.

Javascript solutions preferred, but a python solution would also work. Any help would be appreciated. Thank you!

cs95
  • 379,657
  • 97
  • 704
  • 746

2 Answers2

1

Quickly whipped this up, does it fit your needs?

function GenerateAddends(n){
    if(n == Math.round(n)){
        return [Math.round(n/2),n-Math.round(n/2)];
    }else{
        var len = n.toString().split(".")[1].length
        return [
            Math.round(n/2 * Math.pow(10,len)) / Math.pow(10,len),
            n - Math.round(n/2 * Math.pow(10,len)) / Math.pow(10,len)
        ]
    }
}

console.log(GenerateAddends(7))
console.log(GenerateAddends(7.2))
console.log(GenerateAddends(7.3))
console.log(GenerateAddends(7.25))
console.log(GenerateAddends(7.225))

Alternatively using ECMAScript 2016:

function GenerateAddends(n){
    if(n == Math.round(n)){
        return [Math.round(n/2),n-Math.round(n/2)];
    }else{
        var len = n.toString().split(".")[1].length
        return [
            Math.round(n/2 * 10**len) / 10**len,
            n - Math.round(n/2 * 10**len) / 10**len
        ]
    }
}

console.log(GenerateAddends(7))
console.log(GenerateAddends(7.2))
console.log(GenerateAddends(7.3))
console.log(GenerateAddends(7.25))
console.log(GenerateAddends(7.225))

You'll notice that I had the same thought as you of converting to a string and getting the number of decimal places.

Nick is tired
  • 6,860
  • 20
  • 39
  • 51
1

Here's a python example:

import math

def split_num(num):
    i = 0
    while (num != round(num, i)):  ## NOTE: guaranteed to terminate
        i = i + 1
    p1 = math.ceil( ( 10**i * num ) / 2) / 10**i  ## using 10**i rounds to the appropriate decimal place
    return (p1, num - p1)

## test output
if __name__ == "__main__":
    print(split_num(10))
    print(split_num(10.1))
    print(split_num(10.12))
    print(split_num(10.123))
    print(split_num(10.1234))
    print(split_num(7.3))

>>> python split_num.py
(5.0, 5.0)
(5.1, 5.0)
(5.06, 5.06)
(5.062, 5.060999999999999)
(5.0617, 5.0617)
(3.7, 3.5999999999999996)
gariepy
  • 3,576
  • 6
  • 21
  • 34