Home > Software engineering >  how to discriminate two numbers that are very near?
how to discriminate two numbers that are very near?

Time:04-15

So my case goes like this, my software that is being develop on JavaScript needs to manipulate exact numeric values but sometimes it can happen that the values are way too near and I need to discriminate.

This is a case example:

0:(2) [112.02598008561951, 9.12963236661007]
1:(2) [112.02598008561952, 9.129632366610064]
2:(2) [9.751846481442218, 3.5376744911193576] 

In this array position 0 and 1 has similar values but with an slight difference at the end of the decimals, but the one that counts is the position 0, because the two numbers are way near it messes with the process that follows next.

So, how do I do to discriminate near numbers and just use the first of the similar numbers given?

In the end the end result would be an array like this:

0:(2) [112.02598008561951, 9.12963236661007]
1:(2) [9.751846481442218, 3.5376744911193576] 

I tried doing a truncation but I need the whole number to work with.

Edit: as one of the comments asked about if the points can vary or not, in my real problem I get a series of numbers that I sort normally I get like 3 points or best case scenario I get 2 points.

Sometimes this problem happens when I get near numbers and the first layer of sorting doesn't work as intended and the next part doesn't work well.

In short, you need to consider that it is always like 3 positions of coordinates.

CodePudding user response:

In short your easiest option is to round to a fixed number of decimal places. This is because floats in JS (and in computer science in general) can be a tricky thing. For example, this should make you want to throw your computer:

var x = 0.1 * 0.2; //-> 0.020000000000000004

There are different use cases for needing super exact precision (eg. when dealing with money, trajectory of a satellite, etc), but most use cases only need "good enough" precision. In your case, it's best to round all of your numbers to a fixed decimal length so that you don't encounter the low-level inaccuracies.

var ACCURACY = 100000000;
var round= (num) => Math.round(num * ACCURACY) / ACCURACY;
var x = round(0.1 * 0.2); //-> 0.2

If you trust the numbers you have and you're just needing to filter out a pair which is close to another pair, you will need to write a little function to apply your heuristics.

var areClose = (x, y) => Math.abs(x - y) < 0.0000000001;
var filterPoints = (arr) => {
  return arr.filter(([x, y], i) => {
    for(var n = i - 1; n >= 0; n--) {
      if (areClose(x, arr[n][0]) && areClose(y, arr[n][1])) {
        return false;
      }
    }
    return true;
  });
}

filterPoints([
  [112.02598008561951, 9.12963236661007],
  [112.02598008561952, 9.129632366610064],
  [9.751846481442218, 3.5376744911193576],
]);

// [
//   [112.02598008561951, 9.12963236661007], 
//   [9.751846481442218, 3.5376744911193576]]
// ]

Note: this will keep the "first" set of values. If you wish to keep the "last" set, then you can flip the inner loop to crawl upwards:

for(var n = i   1; n < arr.length; n  ) { ...

CodePudding user response:

Let's see if I understood correctly, you have this array with vertex points, usually it's just a 2 elements bidimensional array, but sometimes it might receive an extra vertex points array, with a slight different value (differ of 1*10^-14) and you want to discard the higher extra values.

I came up with something like this:

const arr = [
  [112.02598008561951, 9.12963236661007],
  [112.02598008561952, 9.129632366610064],
  [9.751846481442218, 3.5376744911193576],
];

for (let i = 0; i < arr.length-1; i  ) {
  const diff =  Math.abs(arr[i][0] - arr[i   1][0])
  if (diff <= 0.00000000000002) arr.splice(i   1, 1);
}

console.log("NEW ARR", arr)

This just checks the first element of the array, since if I understood correctly it automatically means even the second element differs of a similar amount. I'm using a (2*10-14) threshold since 1 is not enough, not sure if it's due to JS issues with float precision.

CodePudding user response:

What about something like

const removeDecimalPlaces = (num) => Math.floor(num * 10000000000000) / 10000000000000;

console.log(removeDecimalPlaces(112.02598008561951) === removeDecimalPlaces(112.02598008561952))

CodePudding user response:

You could sort and reduce

let arr = [
  [112.02598008561952, 9.129632366610064],
  [112.02598008561951, 9.12963236661007],
  [9.751846481442218, 3.5376744911193576]
]
arr.sort((a,b) => a[0]-b[0]); // swap a and b for descending

const precision = 0.00000000000002;
arr = arr.reduce((acc,cur,i) => {
  if (i===0) { acc.push(cur); return acc}
  const diff = Math.abs(acc[acc.length-1][0]-cur[0])
  if (diff > precision) acc.push(cur)
  return acc
},[])

console.log(arr)

  • Related