0

After I build a JS function that generates pseudo numbers from initial seed I created the same function in C# expecting to get the same results. After 6 iterations the results where different... Can someone help me to build such a function that generates same values in JS and also in C# ?

using System;

public class PSR
{
    public int ITN { get; private set; } = 0;
    public int IntITN { get; private set; } = 0;

    private double seed;

    public PSR(double seed)
    {
        this.seed = seed + 0.5;  // avoid 0
    }

    public double Next()
    {
        ITN++;
        var x = Math.Sin(this.seed) * 1000;
        var result = x - Math.Floor(x);  // [0.0,1.0)
        this.seed = result;  // for next call
        return result;
    }

    public double NextInt(double lo, double hi)
    {
        IntITN++;
        var x = this.Next();
        return Math.Truncate((hi - lo) * x + lo);
    }

}

TS version

export class Psr
{
  itn: number = 0;
  intItn:number = 0;
  constructor(private seed) {
    this.seed = seed + 0.5;  // avoid 0
  }

  next() {
    this.itn++
    let x = Math.sin(this.seed) * 1000;
    let result = x - Math.floor(x);  // [0.0,1.0)
    this.seed = result;  // for next call
    return result;
  }

  nextInt(lo, hi) {
    this.intItn++
    let x = this.next();
    return Math.trunc((hi - lo) * x + lo);
  }
}
Gabriel Luca
  • 207
  • 2
  • 10
  • 5
    javascript and c# may have different implementations of the trigonometry functions you're using. – TKoL Nov 14 '19 at 12:30
  • _"After 6 iterations the results where different"_ how different were they? Just a little rounding error or completely different league? – Fildor Nov 14 '19 at 12:34
  • 1
    What is the requirement which forces you to do it? Or is it just curiosity? – mtkachenko Nov 14 '19 at 12:35
  • @Fildor just tested it. First iteration has an error at the 15th decimal place. At the 8th iteration the errors accumulated up to the first decimal place. It is unusable. – Thomas Nov 14 '19 at 12:46
  • So, I would guess it's a difference in implementation that affects accuracy and the error is adding up... not much that can be done to synchronize, I think. Time for Plan B. – Fildor Nov 14 '19 at 12:49
  • 1
    Is RFC-6238 TOTP an option? You would have to use the same time step in both, and the same secret key, but they would generate the same number for both implementations. https://tools.ietf.org/html/rfc6238 This is the standard for two-factor auth pass codes used by apps like Google Authenticator. – Josh Nov 14 '19 at 13:44
  • @Josh dose it work for JS also ? – Gabriel Luca Nov 14 '19 at 14:21
  • It should. The only caveat is that you have to have the same secret and moving factor across both systems (Used by the underlying RFC-4226 implementation). For RFC-6238, that moving factor is time steps since epoch, and by default the time step length is 30 seconds. So, codes generated with the same secret, in the same time step, would be the same across all systems as long as you follow the algorithm. – Josh Nov 14 '19 at 14:34
  • The other downside is that if you are generating keys in rapid succession, they would generate the same code for that entire timestep. If you have a counter that can be syncronized across both systems, you could just use RFC-4226 and have the moving factor be a counter you control. – Josh Nov 14 '19 at 14:34
  • I would go to wikipadia or Knuth to find a common alg and nice seed numbers. Trigonometry seems a bad idea for cross-library compatability. - Do note that many libs do not event guarantee stable results between versions! – TaW Nov 15 '19 at 18:02

1 Answers1

0

I don't have an environment with C# to test with, but something like a simple LCG should works in both.

In JavaScript you might have an implementation like:

const random  = (seed = 3) => () => (seed = (seed * 1103515245 + 12345) % 0xffffffff) / 0xfffffff

const prng = random(); // 3 as default seed

for (let i = 0; i < 100; i ++)
  console.log(prng());

That shouldn't give much issues in any languages to be implemented.

ZER0
  • 24,846
  • 5
  • 51
  • 54
  • In my code I replaced Next to returm: return (seed = (seed * 1103515245 + 12345) % 0xffffffff) / 0xfffffff; in C# the values are similar but not the same I think the error will propagate – Gabriel Luca Nov 14 '19 at 14:02