I write a mathematical function to be benchmark function in my optimization algorithm.

```
public static double SolomonFunction(double[] x)
{
double f;
double sum = 0;
for (int i = 0; i < x.Length; i++)
{
sum += x[i] * x[i];
}
f = 1 - Math.Cos(2 * Math.PI * Math.Sqrt(sum)) + 0.1 * Math.Sqrt(sum);
return f;
}
```

but it has different result in console application and windows application when the input is `SolomonFunction(new double[] { -4.74641638144941E+151, -6.49440696607247E+153, -1.0998592442531E+153, 3.58027097738642E+149, 6.28490996716059E+152 })`

in console application the result is `6,616968044816507E+152`

in windows application the result is `-4,09139395927863E+154`

Is there something different that I need to do in a windows application that I don't need to do in a console application? Or am I fundamentally misunderstanding something?

·

Santiago Trujillo

In the platform that produces “-4,09139395927863E+154”, the `Math.Cos`

routine is broken. It apparently uses a processor instruction that does not support operands outside [−2^{−63}, +2^{−63}].

Since I do not use C#, here is a C program that reproduces the correct behavior:

```
#include <math.h>
#include <stdio.h>
static double SolomonFunction(size_t length, double *x)
{
double sum = 0;
for (int i = 0; i < length; i++)
sum += x[i] * x[i];
return 1 - cos(2 * M_PI * sqrt(sum)) + 0.1 * sqrt(sum);
}
#define NumberOf(a) (sizeof (a) / sizeof *(a))
int main(void)
{
double x[] = { -4.74641638144941E+151, -6.49440696607247E+153, -1.0998592442531E+153, 3.58027097738642E+149, 6.28490996716059E+152 };
printf("%.16g\n", SolomonFunction(NumberOf(x), x));
}
```

When run with Apple Clang 11 on macOS 10.14.6, this produces “6.616968044816507e+152”. Looking at the calculations, we can see that `sum`

must be huge and the result should be entirely dominated by `0.1 * Math.Sqrt(sum)`

. Since the range of cosine on real numbers in [−1, +1], the `1 - Math.Cos(…)`

part of the formula should have negligible effect, regardless of the argument to `Math.Cos`

. So this seems like a reasonable result.

Considering the other result, “-4,09139395927863E+154”, we see it is impossible for the formula to produce a negative result when correctly calculated. `1 - Math.Cos(…)`

should be in [0, 2], and `0.1 * Math.Sqrt(sum)`

should never be negative, so their sum should be non-negative.

This incorrect result is entirely explained by a defective `Math.Cos`

. Suppose, when the argument is huge, `Math.Cos`

returns its argument instead of its cosine. We can reproduce this with the C code above b y using `return 1 - (2 * M_PI * sqrt(sum)) + 0.1 * sqrt(sum);`

, where `cos`

has been removed, leaving just its argument. Running this produces the output “-4.091393959278625e+154”, matching the reported output (with rounding to a different number of digits), confirming the hypothesis.

This is consistent with behavior of the `FCOS`

instruction. Intel 64 and IA-32 Architecture Software Developer‘s Manual, combined volumes, December 2017, page 906, says, for `FCOS`

:

If the source operand is outside the acceptable range, the C2 flag in the FPU status word is set, and the value in register ST(0) remains unchanged.

Thus, when the cosine argument is out of the supported range (−2^{63} to +2^{63}), executing `FCOS`

leaves the argument in the register that is also used for the result. Then `Math.Cos`

apparently uses this value for the result.

·
Santiago Trujillo
Report

Loading