Find original number (Facebook user ID) that got changed by double data type rounding C#

320 Views Asked by At

I developed an application in which user's Facebook name and user ID is saved as an authentication system.

I saved the IDs as double values in a C# script. But as it turns out, the newer Facebook users' IDs are more than 15 digits, which is the limit for double data types without rounding (which I didn't know while in development, ouch!). So the numbers got rounded and values changed drastically. Interestingly, the rounded numbers are of 16 digits and they are not the real user IDs of the users who logged in.

I changed the code after I realized this mistake, but there's no way to find out the users who already logged in before.

I want to know whether I can find the original number from the 16 digit rounded double number that I have now? I'm all ears.

1

There are 1 best solutions below

1
On

As already indicated in a comment on the question, there is no way to recover the original input from the double and it would be better to treat it as a string.

The problem is that, for 9,007,199,254,740,992 and greater, two or more integers map to the same double. The exact value of the double is one of them.

However, that does not mean all is lost for your application. For 16 and 17 digit integers, only a few integers map to each double. The chances of two accounts having the same name and different IDs that map to the same double is low. Treat the double as a one-way hash of the original ID. Each time you need to authenticate and the stored double is at least 9,007,199,254,740,992 you will need to obtain the ID, convert it to double, and accept if it matches. You should also store the ID as a string for future checks.

Given a double, it is possible to find the range of longs, if any, that would map to that double on conversion. If you need to go beyond the long range, use some extended integer type instead. Unfortunately, I don't know enough C# to write it in that language. Here is a Java version:

  /*
   * Return range of longs that all map to d on conversion, null
   * if there is no such long.
   */
  private static long[] getLongRange(double d) {
    long[] result = new long[2];
    long center = (long)d;
    if(center != d){
      return null;
    }
    for(long lower = center; (double)lower == d; lower--){
      result[0] = lower;
    }
    for(long upper = center; (double)upper == d; upper++){
      result[1] = upper;
    }
    return result;
  }