Dear VM experts, I originally asked the question below on pharo-users. Basically I am looking for a way to set the IEEE founding mode for fp-operations at runtime from the image. Best, Steffen Original mail to pharo-users: Hi, is there any way to set the rounding mode for IEEE floating point operations? Maybe something like > Double roundToMinusInfWhile: [... code goes here ...] > Double roundToZeroWhile: [... more code here ...] If not, is it possible to add this behavior, e.g., via a custom primitive? Best, Steffen |
Hi Steffen, As always, there are two ways to do this: via FFI or by writing a plugin (which would implement the primitive). For this case, FFI is probably easier to use. On POSIX platforms, you can call the fegetround/fesetround C99 functions to get/set the rounding mode. I have got no idea how to use FFI in Pharo, but in Squeak it would be as simple as writing these two methods: currentRoundingMode <cdecl: long 'fegetround' (void) module: 'libm'> ^self externalCallFailed setRoundingModeTo: newMode "Set the rounding mode to newMode. Return zero on success, nonzero on failure/unsupported mode. Modes: 0 Rounding is toward 0. 1 Rounding is toward nearest number. 2 Rounding is toward positive infinity. 3 Rounding is toward negative infinity. " <cdecl: long 'fesetround' (long) module: 'libm'> ^self externalCallFailed Note that your platform may not support some rounding modes, and changing the rounding mode may affect other parts of the VM. Here's a quote from the GNU documentation about rounding modes: "You should avoid changing the rounding mode if possible. It can be an expensive operation; also, some hardware requires you to compile your program differently for it to work. The resulting code may run slower. See your compiler documentation for details." So, you might have to tweak compiler flags and compile your own VM if things don't work out of the box. You might also find this answer helpful: https://stackoverflow.com/questions/6867693/change-floating-point-rounding-mode#6867722 Levente On Wed, 23 May 2018, Steffen Märcker wrote: > > Dear VM experts, > > I originally asked the question below on pharo-users. Basically I am > looking for a way to set the IEEE founding mode for fp-operations at > runtime from the image. > > Best, Steffen > > > Original mail to pharo-users: > > Hi, > > is there any way to set the rounding mode for IEEE floating point > operations? Maybe something like > >> Double roundToMinusInfWhile: [... code goes here ...] >> Double roundToZeroWhile: [... more code here ...] > > If not, is it possible to add this behavior, e.g., via a custom primitive? > > Best, Steffen > |
Interesting! Are you after Interval arithmetic or something more complex? Don't forget that the activeProcess can be preempted - if a higher priority Process gets ready - if it waits for a Semaphore - if it explicitely yields and a process with same priority is ready So Double roundToMinusInfWhile: [... code goes here ...] could have side effects on concurrent Process... Unless the rounding mode is made a Process specific variable and that the ProcessorScheduler cares to restore appropriate rounding mode on Process switch if they differ... If the switch is too expensive, it could be differed until a floating point primitive is invoked (unfortunately FFI and plugins would have to be protected too). Note that I have played with computation of residual errors on main operations (+ - * / sqrt) with fma or Kahan-sum-like technics. This code could also be used for fully emulating some rounding mode at image side. If it's only for Interval arithmetic, an image side solution could scale (more expensive than native hardware, but it's to be tested on macro-benchmark). Tell me if your are interested. Also note that unless you use some correctly rounded libm for the sin/cos/exp/ln... primitives (CRLIBM for example), then there is no much guaranty on the behaviour of these functions. The algorithm for Float>>raisedTo: and even raisedToInteger: is quite naive too, and will cumulate several ulp errors that a good libm/pow would not. Please keep us informed on your progress :) Nicolas 2018-05-23 19:23 GMT+02:00 Levente Uzonyi <[hidden email]>:
|
In reply to this post by Levente Uzonyi
Hi Levente, I managed to change the rounding mode via an FFI call (Pharo, OSX). However, the change seem to be not persistent/reliable, as the issues below suggest. I suspect some context switching/restauration to be the cause. Do you maybe have an idea what's going on? Best, Steffen Am .05.2018, 13:26 Uhr, schrieb Steffen Märcker <[hidden email]>: > Hi, > > now I've observed the same issue. It might be related to context > switching, since introducing a delay has a similar effect. Consider: > > | FE_TONEAREST FE_DOWNWARD FE_UPWARD FE_TOWARDZERO | > FE_TONEAREST := 16r0000. > FE_DOWNWARD := 16r0400. > FE_UPWARD := 16r0800. > FE_TOWARDZERO := 16r0C00. > "For some reasons we have to call fegetround once." > "c := LibC new fegetround." > LibC new fesetround: FE_DOWNWARD. > (Delay forSeconds: 1) wait. > v1 := 1.0/10.0. > LibC new fesetround: FE_UPWARD. > v2 := 1.0/10.0. > LibC new fesetround: FE_TONEAREST. > v1 < v2. > > If the delay is inserted, the script evaluates to false. Using the same > LibC-instance or creating a new one does not seem to change anything > here. Interestingly, a similar approach in VisualWorks does not show > this issue yet. > > Actually, I expect the FE_* macros to be platform/implementation > dependent, as suggested here: > http://www.enseignement.polytechnique.fr/informatique/INF478/docs/Cpp/en/c/numeric/fenv/FE_round.html > > [...] > > Am .05.2018, 11:57 Uhr, schrieb Serge Stinckwich > <[hidden email]>: > >> What is really strange is when I print the following lines, I obtain >> 2048: >> >> current := LibC uniqueInstance fegetround. >> LibC uniqueInstance fesetround: 2048. >> LibC uniqueInstance fegetround. >> >> and 0 when I remove the first line : >> LibC uniqueInstance fesetround: 2048. >> LibC uniqueInstance fegetround. >> >> [...] >> >>> On Thu, May 24, 2018 at 10:31 AM Steffen Märcker <[hidden email]> >>> wrote: >>> >>>> I actually made progress: It works like a charm! Basically, I >>>> implemented >>>> the same code as you. Testing is straightforward (using the constant >>>> values from libc): >>>> >>>> current := LibC fegetround. >>>> LibC fesetround: FE_DOWNWARDS. >>>> v1 := 1.0/10.0. >>>> LibC feesetround: FE_UPWARDS. >>>> v2 := 1.0/10.0. >>>> LibC feesetround: current. >>>> v1 < v2. "true" >>>> >>>> > but apparently nothing happens when you do : >>>> > LibC uniqueInstance fesetround: 1024. >>>> > LibC uniqueInstance fegetround. >>>> > always return 0. >>>> >>>> This is expected, since the fesetround function returns 0 only if the >>>> set >>>> operation was successful. |
Hi Steffen, I can only guess that there's some library (IIRC Pharo uses e.g. FreeType) used by the VM setting the rounding mode for its own purposes. I would try to see if the rounding mode stays the same while vmParameter 56 (number of process switches since startup) stays the same. And if it does, I'd use that to minimize the number of times the FFI call has to be done to have the rounding mode you need. Because polling the parameter is probably faster than the FFI call. Levente On Thu, 24 May 2018, Steffen Märcker wrote: > > Hi Levente, > > I managed to change the rounding mode via an FFI call (Pharo, OSX). > However, the change seem to be not persistent/reliable, as the issues > below suggest. I suspect some context switching/restauration to be the > cause. Do you maybe have an idea what's going on? > > Best, Steffen > > > Am .05.2018, 13:26 Uhr, schrieb Steffen Märcker <[hidden email]>: > >> Hi, >> >> now I've observed the same issue. It might be related to context >> switching, since introducing a delay has a similar effect. Consider: >> >> | FE_TONEAREST FE_DOWNWARD FE_UPWARD FE_TOWARDZERO | >> FE_TONEAREST := 16r0000. >> FE_DOWNWARD := 16r0400. >> FE_UPWARD := 16r0800. >> FE_TOWARDZERO := 16r0C00. >> "For some reasons we have to call fegetround once." >> "c := LibC new fegetround." >> LibC new fesetround: FE_DOWNWARD. >> (Delay forSeconds: 1) wait. >> v1 := 1.0/10.0. >> LibC new fesetround: FE_UPWARD. >> v2 := 1.0/10.0. >> LibC new fesetround: FE_TONEAREST. >> v1 < v2. >> >> If the delay is inserted, the script evaluates to false. Using the same >> LibC-instance or creating a new one does not seem to change anything >> here. Interestingly, a similar approach in VisualWorks does not show >> this issue yet. >> >> Actually, I expect the FE_* macros to be platform/implementation >> dependent, as suggested here: >> > http://www.enseignement.polytechnique.fr/informatique/INF478/docs/Cpp/en/c/numeric/fenv/FE_round.html >> >> [...] >> >> Am .05.2018, 11:57 Uhr, schrieb Serge Stinckwich >> <[hidden email]>: >> >>> What is really strange is when I print the following lines, I obtain >>> 2048: >>> >>> current := LibC uniqueInstance fegetround. >>> LibC uniqueInstance fesetround: 2048. >>> LibC uniqueInstance fegetround. >>> >>> and 0 when I remove the first line : >>> LibC uniqueInstance fesetround: 2048. >>> LibC uniqueInstance fegetround. >>> >>> [...] >>> >>>> On Thu, May 24, 2018 at 10:31 AM Steffen Märcker <[hidden email]> >>>> wrote: >>>> >>>>> I actually made progress: It works like a charm! Basically, I >>>>> implemented >>>>> the same code as you. Testing is straightforward (using the constant >>>>> values from libc): >>>>> >>>>> current := LibC fegetround. >>>>> LibC fesetround: FE_DOWNWARDS. >>>>> v1 := 1.0/10.0. >>>>> LibC feesetround: FE_UPWARDS. >>>>> v2 := 1.0/10.0. >>>>> LibC feesetround: current. >>>>> v1 < v2. "true" >>>>> >>>>> > but apparently nothing happens when you do : >>>>> > LibC uniqueInstance fesetround: 1024. >>>>> > LibC uniqueInstance fegetround. >>>>> > always return 0. >>>>> >>>>> This is expected, since the fesetround function returns 0 only if the >>>>> set >>>>> operation was successful. > |
Hi Levente, I'll have a look, thanks for your suggestion! From your description, I assume, libraries as Freetype run in the same process, right? If so, a library changing those process-flags, might cause (maybe hidden) issues at other places as well. Best, Steffen Am .05.2018, 00:43 Uhr, schrieb Levente Uzonyi <[hidden email]>: > Hi Steffen, > I can only guess that there's some library (IIRC Pharo uses e.g. > FreeType) > used by the VM setting the rounding mode for its own purposes. > I would try to see if the rounding mode stays the same while vmParameter > 56 (number of process switches since startup) stays the same. And if it > does, I'd use that to minimize the number of times the FFI call has to > be done to have the rounding mode you need. Because polling the > parameter is probably faster than the FFI call. > Levente |
Free forum by Nabble | Edit this page |