Arithmetic calculation using Linq.Expressions gives different results by 32 vs 64 bit

I observe strange behavior regarding the results of the following code:

namespace Test {
  class Program {
    private static readonly MethodInfo Tan = typeof(Math).GetMethod("Tan", new[] { typeof(double) });
    private static readonly MethodInfo Log = typeof(Math).GetMethod("Log", new[] { typeof(double) });

    static void Main(string[] args) {
    var c1 = 9.97601998143507984195821336470544338226318359375d;
    var c2 = -0.11209109500765944422706610339446342550218105316162109375d;

    var result1 = Math.Pow(Math.Tan(Math.Log(c1) / Math.Tan(c2)), 2);

    var p1 = Expression.Parameter(typeof(double));
    var p2 = Expression.Parameter(typeof(double));
    var expr = Expression.Power(Expression.Call(Tan, Expression.Divide(Expression.Call(Log, p1), Expression.Call(Tan, p2))), Expression.Constant(2d));
    var lambda = Expression.Lambda<Func<double, double, double>>(expr, p1, p2);
    var result2 = lambda.Compile()(c1, c2);

    var s1 = DoubleConverter.ToExactString(result1);
    var s2 = DoubleConverter.ToExactString(result2);

    Console.WriteLine("Result1: {0}", s1);
    Console.WriteLine("Result2: {0}", s2);
  }
}

Code compiled for x64 gives the same result:

Result1: 4888.95508254035303252749145030975341796875
Result2: 4888.95508254035303252749145030975341796875

But when compiling for x86 or Any Cpu, the results are different:

Result1: 4888.95508254035303252749145030975341796875
Result2: 4888.955082542781383381225168704986572265625

Why result1does it remain unchanged, but result2depends on the target architecture? Is there a way to make result1and result2stay the same on the same architecture?

DoubleConverter http://jonskeet.uk/csharp/DoubleConverter.cs. decimal, , , . -.NET 4.5.2, . Visual Studio 2015 Update 1 RC Windows 10.

.

djcouchycouch :

  var c1 = 9.97601998143507984195821336470544338226318359375d;
  var c2 = -0.11209109500765944422706610339446342550218105316162109375d;
  var result1 = Math.Log(c1) / Math.Tan(c2);
  var p1 = Expression.Parameter(typeof(double));
  var p2 = Expression.Parameter(typeof(double));
  var expr = Expression.Divide(Expression.Call(Log, p1), Expression.Call(Tan, p2));
  var lambda = Expression.Lambda<Func<double, double, double>>(expr, p1, p2);
  var result2 = lambda.Compile()(c1, c2);

x86 AnyCpu, :

Result1: -20.43465311535924655572671326808631420135498046875
Result2: -20.434653115359243003013034467585384845733642578125

x64, :

Result1: -20.43465311535924655572671326808631420135498046875
Result2: -20.43465311535924655572671326808631420135498046875

x86 AnyCpu, Release:

Result1: -20.434653115359243003013034467585384845733642578125
Result2: -20.434653115359243003013034467585384845733642578125

x64, Release:

Result1: -20.43465311535924655572671326808631420135498046875
Result2: -20.43465311535924655572671326808631420135498046875

, Debug, Release, x86 x64, , , .

+4
1

ECMA-335 I.12.1.3 :

[...] (, ) . : float32 float64. ( , , ) . float32, float64, / . [...]

@harold , 80- FPU x86. , , , , Release , .

, . , Expression - :

var tmp = new double[2];
tmp[0] = Math.Log(c1);
tmp[1] = Math.Tan(c2);
tmp[0] /= tmp[1];
tmp[0] = Math.Tan(tmp[0]);
tmp[0] = Math.Pow(tmp[0], 2);

tmp[0] .

, .

Expression , , , . Expression.Block, , Expression.Assign .

+3

Source: https://habr.com/ru/post/1616778/


All Articles