0

I would want wine/Linux run programs (i.e. Windows exe/dll running on Linux through wine) to use the same accuracy for Trascendental functions as implemented by Microsoft (i.e. VS2019 etc etc).

The challenge I have is that some software I need to run through wine does call such functions and I'm afraid the accuracy/implementation provided through glibc yields to different numbers and makes the code eventually follow different paths.

I have found a workaround, which is to load ucrtbase.dll as native,builtin as in

WINEDLLOVERRIDES="ucrtbase=n,b" wine <my program>

This works excellent when I run my software through interactive terminal.

Unfortunately if I then run such process as a sub-process (i.e. stdout and stderr redirected to memory/files) then the program crashes because I guess it still believes it's on a terminal and tries to print special color characters, but of course it should not. Of course if I leave the builtin ucrtbase.dll it all works as sub-process, but then I lose accuracy/results.

Any idea how I could proceed next? I would also be ok to recompile some transcendental functions myself inside the builtin wine ucrtbase.dll to be the same as VS2019 (and further) alas not sure the source code is publicly available?

Emanuele
  • 1,408
  • 1
  • 15
  • 39
  • 1
    Precision is not the issue. Nor is accuracy. What you are looking for is reproducibility. Searching for “[floating-point] reproducibility” shows a number of questions on the topic. Precision is the fineness with which the calculations are performed or the results are returned. For the format commonly used for `double`, this is the same for Linux and Windows, aside from any extended-precision calculations used internally to the routines, so precision is not the issue. Accuracy is not the issue because two implementations of a routine may be equally accurate but in different ways… – Eric Postpischil May 12 '23 at 16:52
  • … Due to the nature of the transcendental functions, they are approximated, and the approximations commonly used do not fully provide *correctly rounded* results. There are essentially two ways to get reproducible results for the transcendental functions: Use implementations that provide correctly rounded results, which are necessary the same, or use the same implementation in all versions of your program… – Eric Postpischil May 12 '23 at 16:54
  • … Merely recompiling the same source code may be insufficient for that; you need to ensure the same floating-point operations are performed, but different compilers may compile the same C source code to different assembly, such as using FMA or extended-precision hardware features. – Eric Postpischil May 12 '23 at 16:55
  • I used "precision" as "accuracy", yes you're right I'm not native English speaker. Anyhow, I guess I conveyed the issue I'm facing.Any suggestion specific to wine and not something generic? Respectfully your answer is not useful, is just pedantic. – Emanuele May 12 '23 at 16:55
  • 1
    @Emanuele There was a lot more to Eric's comments than the terminology issue! In particular, the reproducibility issue — and the fact that transcendental functions don't always give correctly rounded results under all implementations — is the root cause of your problem. – Steve Summit May 12 '23 at 17:04
  • As I understand it, it is very hard — nearly impossible — for an implementation to deliver correctly-rounded results for transcendental functions under all circumstances. Others before you have had exactly the same problem, and I have not heard an ideal solution for it. You can either (a) contrive to use exactly the same library implementation everywhere, or (b) make your calculations less sensitive to the least-significant bits somehow. But, depending on your circumstances, neither (a) nor (b) may be a viable option. – Steve Summit May 12 '23 at 17:07
  • Thanks, appreciate, indeed I'm aware of what you wrote. I would be happy to use "Microsoft accuracy", I just need _this_ reproducibility, I'm well aware the MSFT implementation may be potentially less correct than others. I would be more than happy to use the `ucrtbase=n,b` workaround, alas it does crash when executed as child process. I would imagine a technical solution (i.e. the ability somehow to run MSFT x64 log/... code) to fit my bill. – Emanuele May 12 '23 at 17:18
  • Does this help: [How should I do floating point comparison?](https://stackoverflow.com/q/4915462/5382650) – Craig Estey May 12 '23 at 19:07
  • Just an idea. Write a Windows DLL that forward all the transcendental functions, and link it against the *static* CRT. Inject it so that calls to the transcendental functions ultimately go to Microsoft implementations, but do not use the native CRT. – n. m. could be an AI May 12 '23 at 19:22
  • @n.m. that's one thought I had... I wonder if LD_PRELOAD would work with wine PE/dlls – Emanuele May 12 '23 at 19:44
  • @CraigEstey the codebase already has floating point comparison with epsilon/threshold... the challenge is that it's by default very low (e-15) and the _log_ implementation in glibc eventually leads to differences e-9 which may not be palatable. The most irritating aspect is that when I use the ucrtbase _native_ and run the executable from the console, I get the _exact_ same numbers as on Windows native. – Emanuele May 12 '23 at 19:46
  • Is `e-9` okay? If so, the compare function can scale it. Which impl is the most accurate/correct? `glibc` or `wine/realWinX`? What is your goal? WinX compat or correctness? Have you disassembled the T-functions to see if they use fundamentally different impl/inst? From "run the executable from the console ...", is the issue that `wine` is invoked differently (e.g. missing the environment variable)? Can you edit your _question_ and post sample code that shows the issue? (e.g.) Does the calc and `printf` and two compiled programs, one for wine, one for linux. – Craig Estey May 12 '23 at 21:07
  • `e-9` is not okay I'm afraid, should stay around `e-15` or smaller. In terms of code I'll see what i can post - but I'm also tempted to try modifying the functions that print _colors_ on _std::cout_ and see if I can avoid the crash using `ucrtbase=n,b`. – Emanuele May 12 '23 at 21:10
  • Also, _exact_ build and run commands for both environments. If you do that, we [I] can download, build, run the programs. I'm on linux and it would give me an excuse to reinstall `wine` ;-) – Craig Estey May 12 '23 at 21:12
  • I think I managed to work around it. Found out that the crash is due of C++ code using `std::cout` and when not run in a terminal, the _native_ `ucrtbase` ends up not understanding this - hence by _resetting_ the `std::cout` to another `std::fstream` (or closing it), then no crashes happen and one can use the `WINEDLLOVERRIDE` to have access to same transcendental functions. – Emanuele May 15 '23 at 15:54

1 Answers1

0

The most effective and efficient way is to use an original ucrtbase.dll (which contains all the transcendental functions) coming from a Windows install (which of course requires you to have a licensed copy) and add to your wine options such as:

WINEDLLOVERRIDES="ucrtbase=n,b" wine <your program>

This is heavily caveated, because when <your program> will run everything will work as long as it's running from a terminal (or terminal emulator). If instead you have to redirect its output to a file, you will experience memory corruption and/or crashes.

In order to work around this issue, one will have fundamentally two options:

  1. soft-close std::cout and/or std::cerr by calling std::cout.setstate(std::ios_base::eofbit) - nothing will be printed
  2. changing where to output content of std::cout and/or std::cerr by redirecting the same (along the lines of this answer) seems like now this library understands it's not printing to a terminal hence it won't corrupt stream/memory

This should happen inside <your program> and can be easily implemented in via wine by changing one of core DLLs so that the same can get executed upon program startup via DllMain/DLL_PROCESS_ATTACH.

This has been verified with wine 8.0.1 on RHEL 7.9.

Emanuele
  • 1,408
  • 1
  • 15
  • 39