Re: [racket-dev] What are single flonums good for?
At Sun, 16 Sep 2012 17:10:01 -0500, Matthias Felleisen wrote: > Suppose we had started Racket long ago and maintained it until > now. Then we'd be looking at 8bit, 16, 32, and 64 precision. In some N > years from now, we may need 128. (Actually there were machines in the > past that did, but never mind.) > > Could we separate precision and type into separate dimensions so that > we could state types like this: > > ∀ p : precision. FP[p] -> FP[p] > > where we see FP as a type constructor that consumes a precision value > to generate the right kind of type. This might be a dependent type but > it could be a useful one. Of course, it isn't really a parametric form > of polymorphism as Neil's functions show (and better still Vincent's > rewrites). I think row types can give us that, and clean up other parts of the numeric tower, too. That's something we've been thinking about for some time. Vincent _ Racket Developers list: http://lists.racket-lang.org/dev
Re: [racket-dev] What are single flonums good for?
On 09/16/2012 04:10 PM, Matthias Felleisen wrote: Suppose we had started Racket long ago and maintained it until now. Then we'd be looking at 8bit, 16, 32, and 64 precision. In some N years from now, we may need 128. (Actually there were machines in the past that did, but never mind.) Could we separate precision and type into separate dimensions so that we could state types like this: ∀ p : precision. FP[p] -> FP[p] where we see FP as a type constructor that consumes a precision value to generate the right kind of type. This might be a dependent type but it could be a useful one. Of course, it isn't really a parametric form of polymorphism as Neil's functions show (and better still Vincent's rewrites). 80-bit, and then 128-bit flonums are inevitable. After TR has type classes or something like them, this would work really well. The C++ Boost libraries use templates to achieve something similar. Functions with an FPU implementation (sin, exp, etc.) just dispatch to the proper bare-metal function. Functions without an FPU implementation (gamma, erf, etc.) also dispatch depending on precision, but can share implementation details when the algorithms are similar. (Example: the gamma function uses a different Lanczos polynomial for each precision, but always uses it in the same way.) Compositions of either kind are fully polymorphic. Neil ⊥ _ Racket Developers list: http://lists.racket-lang.org/dev
Re: [racket-dev] What are single flonums good for?
Suppose we had started Racket long ago and maintained it until now. Then we'd be looking at 8bit, 16, 32, and 64 precision. In some N years from now, we may need 128. (Actually there were machines in the past that did, but never mind.) Could we separate precision and type into separate dimensions so that we could state types like this: ∀ p : precision. FP[p] -> FP[p] where we see FP as a type constructor that consumes a precision value to generate the right kind of type. This might be a dependent type but it could be a useful one. Of course, it isn't really a parametric form of polymorphism as Neil's functions show (and better still Vincent's rewrites). -- Matthias On Sep 15, 2012, at 9:31 AM, Vincent St-Amour wrote: > At Fri, 14 Sep 2012 23:45:43 -0500, > Robby Findler wrote: >> The original message in this thread suggests that there is a type >> Single-Flonum and that it is making Neil wrangle his code to be >> careful about it. > > Right, TR supports `Single-Flonum's, but not `f32vector's. > > Part of the complexity in Neil's code is due to types, part of it is not. > > Assuming he wrote the math library in untyped Racket: > >(define (foo x) > (cond [(double-flonum? x) (flfoo x)] > [(single-flonum? x) (real->single-flonum > (flfoo (real->double-flonum x)))] > [else (flfoo (real->double-flonum x))])) > > The code is exactly the same as before. The complexity comes from the > fact that this function, when given single-precision inputs, wants to > produce single-precision outputs, hence the special case. > > If Neil wants `foo' to be as flexible as Racket's built-in operations > (which, when given single-precision inputs, produce single-precision > outputs), he needs that special case, types or not. > > If he gives up on that flexibility, things become a lot simpler: > >(define (foo x) > (flfoo (real->double-flonum x))) > > This version still accepts single-precision inputs, but always produces > doubles. > > The types simply mirror that distinction: > >(: foo (case-> (Single-Flonum -> Single-Flonum) >(Flonum -> Flonum) >(Real -> Real))) > > vs > >(: foo (Real -> Flonum)) > > This kind of complexity gets worse for functions with multiple arguments, > and types make it worse. When expressing coercion rules, the > implementation can take shortcuts that the type system cannot currently > express, leading to unwieldy types. > > These issues only come up when writing libraries that aim to propagate > Racket's numeric flexibility, such as the math library or TR's base > environment. Clients of either don't need to worry about any of that. > > Single-precision floats are not the source of this problem (you would > run into the same issues, in both the untyped and typed worlds, with a > function that takes ints to ints and floats to floats), but they do add > one more type to worry about. > > Vincent > _ > Racket Developers list: > http://lists.racket-lang.org/dev _ Racket Developers list: http://lists.racket-lang.org/dev
Re: [racket-dev] What are single flonums good for?
2012/9/15 Robby Findler : > > At this point, I'm still left wondering if Single-Flonums are good for > anything, but I can imagine that they are good for not breaking old > programs, so probably best to leave well enough alone. > One use case for singles is offloading computations to a graphics card. GPUs are heavily optimized for single precision floats, some cards still don't support doubles at all, most have much lower performance with them. _ Racket Developers list: http://lists.racket-lang.org/dev
Re: [racket-dev] What are single flonums good for?
Thanks for the explanation. I see how this is not a typed-specific problem (indeed, it is probably a Good Thing that TR helps us be careful about this distinction when it matters). At this point, I'm still left wondering if Single-Flonums are good for anything, but I can imagine that they are good for not breaking old programs, so probably best to leave well enough alone. Thanks again, Robby On Sat, Sep 15, 2012 at 9:31 AM, Vincent St-Amour wrote: > At Fri, 14 Sep 2012 23:45:43 -0500, > Robby Findler wrote: >> The original message in this thread suggests that there is a type >> Single-Flonum and that it is making Neil wrangle his code to be >> careful about it. > > Right, TR supports `Single-Flonum's, but not `f32vector's. > > Part of the complexity in Neil's code is due to types, part of it is not. > > Assuming he wrote the math library in untyped Racket: > > (define (foo x) >(cond [(double-flonum? x) (flfoo x)] > [(single-flonum? x) (real->single-flonum >(flfoo (real->double-flonum x)))] > [else (flfoo (real->double-flonum x))])) > > The code is exactly the same as before. The complexity comes from the > fact that this function, when given single-precision inputs, wants to > produce single-precision outputs, hence the special case. > > If Neil wants `foo' to be as flexible as Racket's built-in operations > (which, when given single-precision inputs, produce single-precision > outputs), he needs that special case, types or not. > > If he gives up on that flexibility, things become a lot simpler: > > (define (foo x) >(flfoo (real->double-flonum x))) > > This version still accepts single-precision inputs, but always produces > doubles. > > The types simply mirror that distinction: > > (: foo (case-> (Single-Flonum -> Single-Flonum) > (Flonum -> Flonum) > (Real -> Real))) > > vs > > (: foo (Real -> Flonum)) > > This kind of complexity gets worse for functions with multiple arguments, > and types make it worse. When expressing coercion rules, the > implementation can take shortcuts that the type system cannot currently > express, leading to unwieldy types. > > These issues only come up when writing libraries that aim to propagate > Racket's numeric flexibility, such as the math library or TR's base > environment. Clients of either don't need to worry about any of that. > > Single-precision floats are not the source of this problem (you would > run into the same issues, in both the untyped and typed worlds, with a > function that takes ints to ints and floats to floats), but they do add > one more type to worry about. > > Vincent _ Racket Developers list: http://lists.racket-lang.org/dev
Re: [racket-dev] What are single flonums good for?
At Fri, 14 Sep 2012 23:45:43 -0500, Robby Findler wrote: > The original message in this thread suggests that there is a type > Single-Flonum and that it is making Neil wrangle his code to be > careful about it. Right, TR supports `Single-Flonum's, but not `f32vector's. Part of the complexity in Neil's code is due to types, part of it is not. Assuming he wrote the math library in untyped Racket: (define (foo x) (cond [(double-flonum? x) (flfoo x)] [(single-flonum? x) (real->single-flonum (flfoo (real->double-flonum x)))] [else (flfoo (real->double-flonum x))])) The code is exactly the same as before. The complexity comes from the fact that this function, when given single-precision inputs, wants to produce single-precision outputs, hence the special case. If Neil wants `foo' to be as flexible as Racket's built-in operations (which, when given single-precision inputs, produce single-precision outputs), he needs that special case, types or not. If he gives up on that flexibility, things become a lot simpler: (define (foo x) (flfoo (real->double-flonum x))) This version still accepts single-precision inputs, but always produces doubles. The types simply mirror that distinction: (: foo (case-> (Single-Flonum -> Single-Flonum) (Flonum -> Flonum) (Real -> Real))) vs (: foo (Real -> Flonum)) This kind of complexity gets worse for functions with multiple arguments, and types make it worse. When expressing coercion rules, the implementation can take shortcuts that the type system cannot currently express, leading to unwieldy types. These issues only come up when writing libraries that aim to propagate Racket's numeric flexibility, such as the math library or TR's base environment. Clients of either don't need to worry about any of that. Single-precision floats are not the source of this problem (you would run into the same issues, in both the untyped and typed worlds, with a function that takes ints to ints and floats to floats), but they do add one more type to worry about. Vincent _ Racket Developers list: http://lists.racket-lang.org/dev
Re: [racket-dev] What are single flonums good for?
The original message in this thread suggests that there is a type Single-Flonum and that it is making Neil wrangle his code to be careful about it. Robby On Fri, Sep 14, 2012 at 3:55 PM, Jay McCarthy wrote: > TR doesn't support them anyways because there are only typed f64 > vectors and not typed f32 vectors. > > Jay > > On Fri, Sep 14, 2012 at 11:28 AM, Robby Findler > wrote: >> As far as I can tell, if this pollutes TR programs in any interesting >> way, then it would be a cause for concern. >> >> Robby >> >> On Fri, Sep 14, 2012 at 12:21 PM, John Clements >> wrote: >>> >>> On Sep 12, 2012, at 1:03 PM, Jay McCarthy wrote: >>> On Wed, Sep 12, 2012 at 8:31 AM, Neil Toronto wrote: > Compatibility with C code? Why not have the FFI convert them? > > Save space? I can see that. It won't help much if they're sent to math > library functions, though. Those will convert them to flonums and usually > box the converted values. I think these are big deals with respect to libraries that you deliver large float matrices to where you want to efficiently store a big f32vector rather than an f64vector. Examples of this include OpenGL where vector coordinates, colors, etc are typically floats and not doubles. >>> >>> Jay's concern is the same as mine; there are situations (getting rarer) >>> where a huge c-style array of f32s is the only way to interact with a >>> library. For instance, in the extremely popular "JACK" library (Golly, I >>> wish it worked on windows…), "all audio data is represented as 32-bit >>> floating point values" (from their web page). >>> >>> I haven't followed the conversation closely enough to understand the >>> ramifications of the proposed change, though; my guess is that the ffi can >>> still address such arrays, it's just that computing with these values will >>> require coercion. I could be okay with that; based on my understanding of >>> the IEEE floating-point spec, such a translation could be pretty fast; >>> 32bit -> 64bit looks like it would just be adding zeros, and 32bit to 64bit >>> would require checking for exponent overflow; either way, this sounds like >>> something that might be done on-chip by modern processors, and in fact >>> might *already* be taking place in floating point 32-bit operations. >>> (Anyone know whether Intel chips internally represent 32-bit floats as >>> 64-bit ones?) >>> >>> John >>> >>> >>> _ >>> Racket Developers list: >>> http://lists.racket-lang.org/dev >>> > > > > -- > Jay McCarthy > Assistant Professor / Brigham Young University > http://faculty.cs.byu.edu/~jay > > "The glory of God is Intelligence" - D&C 93 _ Racket Developers list: http://lists.racket-lang.org/dev
Re: [racket-dev] What are single flonums good for?
TR doesn't support them anyways because there are only typed f64 vectors and not typed f32 vectors. Jay On Fri, Sep 14, 2012 at 11:28 AM, Robby Findler wrote: > As far as I can tell, if this pollutes TR programs in any interesting > way, then it would be a cause for concern. > > Robby > > On Fri, Sep 14, 2012 at 12:21 PM, John Clements > wrote: >> >> On Sep 12, 2012, at 1:03 PM, Jay McCarthy wrote: >> >>> On Wed, Sep 12, 2012 at 8:31 AM, Neil Toronto >>> wrote: Compatibility with C code? Why not have the FFI convert them? Save space? I can see that. It won't help much if they're sent to math library functions, though. Those will convert them to flonums and usually box the converted values. >>> >>> I think these are big deals with respect to libraries that you deliver >>> large float matrices to where you want to efficiently store a big >>> f32vector rather than an f64vector. Examples of this include OpenGL >>> where vector coordinates, colors, etc are typically floats and not >>> doubles. >> >> Jay's concern is the same as mine; there are situations (getting rarer) >> where a huge c-style array of f32s is the only way to interact with a >> library. For instance, in the extremely popular "JACK" library (Golly, I >> wish it worked on windows…), "all audio data is represented as 32-bit >> floating point values" (from their web page). >> >> I haven't followed the conversation closely enough to understand the >> ramifications of the proposed change, though; my guess is that the ffi can >> still address such arrays, it's just that computing with these values will >> require coercion. I could be okay with that; based on my understanding of >> the IEEE floating-point spec, such a translation could be pretty fast; 32bit >> -> 64bit looks like it would just be adding zeros, and 32bit to 64bit would >> require checking for exponent overflow; either way, this sounds like >> something that might be done on-chip by modern processors, and in fact might >> *already* be taking place in floating point 32-bit operations. (Anyone know >> whether Intel chips internally represent 32-bit floats as 64-bit ones?) >> >> John >> >> >> _ >> Racket Developers list: >> http://lists.racket-lang.org/dev >> -- Jay McCarthy Assistant Professor / Brigham Young University http://faculty.cs.byu.edu/~jay "The glory of God is Intelligence" - D&C 93 _ Racket Developers list: http://lists.racket-lang.org/dev
Re: [racket-dev] What are single flonums good for?
Two hours ago, John Clements wrote: > > I haven't followed the conversation closely enough to understand the > ramifications of the proposed change, though; my guess is that the > ffi can still address such arrays, it's just that computing with > these values will require coercion. I could be okay with that; based > on my understanding of the IEEE floating-point spec, such a > translation could be pretty fast; 32bit -> 64bit looks like it would > just be adding zeros, and 32bit to 64bit would require checking for > exponent overflow; either way, this sounds like something that might > be done on-chip by modern processors, and in fact might *already* be > taking place in floating point 32-bit operations. (Anyone know > whether Intel chips internally represent 32-bit floats as 64-bit > ones?) The main cost is that such a back-and-forth translation will require allocation. -- ((lambda (x) (x x)) (lambda (x) (x x))) Eli Barzilay: http://barzilay.org/ Maze is Life! _ Racket Developers list: http://lists.racket-lang.org/dev
Re: [racket-dev] What are single flonums good for?
As far as I can tell, if this pollutes TR programs in any interesting way, then it would be a cause for concern. Robby On Fri, Sep 14, 2012 at 12:21 PM, John Clements wrote: > > On Sep 12, 2012, at 1:03 PM, Jay McCarthy wrote: > >> On Wed, Sep 12, 2012 at 8:31 AM, Neil Toronto wrote: >>> Compatibility with C code? Why not have the FFI convert them? >>> >>> Save space? I can see that. It won't help much if they're sent to math >>> library functions, though. Those will convert them to flonums and usually >>> box the converted values. >> >> I think these are big deals with respect to libraries that you deliver >> large float matrices to where you want to efficiently store a big >> f32vector rather than an f64vector. Examples of this include OpenGL >> where vector coordinates, colors, etc are typically floats and not >> doubles. > > Jay's concern is the same as mine; there are situations (getting rarer) where > a huge c-style array of f32s is the only way to interact with a library. For > instance, in the extremely popular "JACK" library (Golly, I wish it worked on > windows…), "all audio data is represented as 32-bit floating point values" > (from their web page). > > I haven't followed the conversation closely enough to understand the > ramifications of the proposed change, though; my guess is that the ffi can > still address such arrays, it's just that computing with these values will > require coercion. I could be okay with that; based on my understanding of the > IEEE floating-point spec, such a translation could be pretty fast; 32bit -> > 64bit looks like it would just be adding zeros, and 32bit to 64bit would > require checking for exponent overflow; either way, this sounds like > something that might be done on-chip by modern processors, and in fact might > *already* be taking place in floating point 32-bit operations. (Anyone know > whether Intel chips internally represent 32-bit floats as 64-bit ones?) > > John > > > _ > Racket Developers list: > http://lists.racket-lang.org/dev > _ Racket Developers list: http://lists.racket-lang.org/dev
Re: [racket-dev] What are single flonums good for?
On Sep 12, 2012, at 1:03 PM, Jay McCarthy wrote: > On Wed, Sep 12, 2012 at 8:31 AM, Neil Toronto wrote: >> Compatibility with C code? Why not have the FFI convert them? >> >> Save space? I can see that. It won't help much if they're sent to math >> library functions, though. Those will convert them to flonums and usually >> box the converted values. > > I think these are big deals with respect to libraries that you deliver > large float matrices to where you want to efficiently store a big > f32vector rather than an f64vector. Examples of this include OpenGL > where vector coordinates, colors, etc are typically floats and not > doubles. Jay's concern is the same as mine; there are situations (getting rarer) where a huge c-style array of f32s is the only way to interact with a library. For instance, in the extremely popular "JACK" library (Golly, I wish it worked on windows…), "all audio data is represented as 32-bit floating point values" (from their web page). I haven't followed the conversation closely enough to understand the ramifications of the proposed change, though; my guess is that the ffi can still address such arrays, it's just that computing with these values will require coercion. I could be okay with that; based on my understanding of the IEEE floating-point spec, such a translation could be pretty fast; 32bit -> 64bit looks like it would just be adding zeros, and 32bit to 64bit would require checking for exponent overflow; either way, this sounds like something that might be done on-chip by modern processors, and in fact might *already* be taking place in floating point 32-bit operations. (Anyone know whether Intel chips internally represent 32-bit floats as 64-bit ones?) John smime.p7s Description: S/MIME cryptographic signature _ Racket Developers list: http://lists.racket-lang.org/dev
Re: [racket-dev] What are single flonums good for?
On Wed, Sep 12, 2012 at 3:47 PM, Matthew Flatt wrote: > At Wed, 12 Sep 2012 08:31:29 -0600, Neil Toronto wrote: >> Why do we have these things? > > I'm not sure this reason from 1996 is still relevant, but FWIW: > Originally, there were drawing-related `float' computations in C code > that I wanted to replicate exactly in Racket (ok, MzScheme). > Eventually, I solved my specific consistency problem by changing the C > code to use `double's; in other cases, someone might not be free to > change the calculation. Would today's FFI make it easy (enough) to do those precise calculations? (Or maybe if we added a little library to help?) Robby _ Racket Developers list: http://lists.racket-lang.org/dev
Re: [racket-dev] What are single flonums good for?
At Wed, 12 Sep 2012 08:31:29 -0600, Neil Toronto wrote: > Why do we have these things? I'm not sure this reason from 1996 is still relevant, but FWIW: Originally, there were drawing-related `float' computations in C code that I wanted to replicate exactly in Racket (ok, MzScheme). Eventually, I solved my specific consistency problem by changing the C code to use `double's; in other cases, someone might not be free to change the calculation. _ Racket Developers list: http://lists.racket-lang.org/dev
Re: [racket-dev] What are single flonums good for?
On Wed, Sep 12, 2012 at 8:31 AM, Neil Toronto wrote: > Compatibility with C code? Why not have the FFI convert them? > > Save space? I can see that. It won't help much if they're sent to math > library functions, though. Those will convert them to flonums and usually > box the converted values. I think these are big deals with respect to libraries that you deliver large float matrices to where you want to efficiently store a big f32vector rather than an f64vector. Examples of this include OpenGL where vector coordinates, colors, etc are typically floats and not doubles. Jay -- Jay McCarthy Assistant Professor / Brigham Young University http://faculty.cs.byu.edu/~jay "The glory of God is Intelligence" - D&C 93 _ Racket Developers list: http://lists.racket-lang.org/dev
Re: [racket-dev] What are single flonums good for?
On Wed, Sep 12, 2012 at 11:24 AM, Vincent St-Amour wrote: > Single-precision float support used to be enabled via a configure > option, which meant that some Racket installations would support them, > and some would not. > > Since zo files are meant to be portable, they could not contain > single-precision floats. So, compilation would promote single literals > to doubles. > > This meant that compilation could change the behavior of a program. > Here's an example: > > stamourv@ahuntsic:small-float-test$ cat test2.rkt > #lang racket > (define (f x) (displayln (flonum? x))) > (f (if (with-input-from-string "#t" read) 1.0f0 2.0f0)) > stamourv@ahuntsic:small-float-test$ racket test2.rkt > #f > stamourv@ahuntsic:small-float-test$ raco make test2.rkt > stamourv@ahuntsic:small-float-test$ racket test2.rkt > #t > stamourv@ahuntsic:small-float-test$ > > This example has to be a bit convoluted to defeat constant folding, > which makes the problem disappear: > > stamourv@ahuntsic:small-float-test$ cat test.rkt > #lang racket > (flonum? 1.0f0) > stamourv@ahuntsic:small-float-test$ racket test.rkt > #f > stamourv@ahuntsic:small-float-test$ raco make test.rkt > stamourv@ahuntsic:small-float-test$ racket test.rkt > #f > stamourv@ahuntsic:small-float-test$ raco decompile test.rkt > (begin > (module test > (#%apply-values |_print-values@(lib "racket/private/modbeg.rkt")| > '#f))) > stamourv@ahuntsic:small-float-test$ > > This can make for pretty elusive bugs. This gets especially problematic > when you add unsafe float operations to the mix, which can turn these > issues into segfaults. > > The solution we picked was to support single-precision floats by default > and to allow them in zos, which makes these discrepancies go away. > > I agree that having to handle single floats when reasoning about numbers > complicates things, and it annoys me too. But I still think it's less > problematic than what I describe above. This rationale does not explain why we have single precision floats at all, tho. Robby _ Racket Developers list: http://lists.racket-lang.org/dev
Re: [racket-dev] What are single flonums good for?
Two hours ago, Stephen Bloch wrote: > > Would it be even less problematic to get rid of them entirely, > except in FFI? (They're not really an issue for the FFI, since you'd just translate the numbers to them when needed. IOW, racket doesn't even need exact integers to have an FFI with them.) -- ((lambda (x) (x x)) (lambda (x) (x x))) Eli Barzilay: http://barzilay.org/ Maze is Life! _ Racket Developers list: http://lists.racket-lang.org/dev
Re: [racket-dev] What are single flonums good for?
On 09/12/2012 10:24 AM, Vincent St-Amour wrote: I agree that having to handle single floats when reasoning about numbers complicates things, and it annoys me too. But I still think it's less problematic than what I describe above [compilation could change the behavior > of a program]. Interesting! I think the least problematic solution would be to separate them from the rest of the numeric tower, and give them their own set of single-flonum-only functions: sf+, sfabs, etc. They could even operate on single-precision complex numbers. Hindsight, etc., though. (: foo (case-> (Single-Flonum -> Single-Flonum) (Flonum -> Flonum) (Real -> Real))) (define (foo x) (cond [(double-flonum? x) (flfoo x)] [(single-flonum? x) (real->single-flonum (flfoo (real->double-flonum x)))] [else (flfoo (real->double-flonum x))])) This function already converts rationals to doubles, and it seems `flfoo' produces doubles too. You could drop the second clause, always produce doubles, change the type to `(Real -> Flonum)' and leave the conversion to single to the client. Since the math library always operates on doubles internally anyway, this would also eliminate unnecessary conversions to singles between stages of a pipeline. It's not just slower. The unnecessary conversions lose precision because of double rounding. I hadn't thought of that yet, so thanks. Why do we have these things? I don't know why they were added originally (as an option). In my limited experience, I don't think I've seen non-test code that uses them. This gets at the design decision I'm facing now. Would anybody care if the math library just treated them like other non-double-flonum reals, and made no effort to preserve single-flonum-ness? I'm leaning toward doing that now. Neil ⊥ _ Racket Developers list: http://lists.racket-lang.org/dev
Re: [racket-dev] What are single flonums good for?
On Sep 12, 2012, at 12:24 PM, Vincent St-Amour wrote: > Single-precision float support used to be enabled via a configure > option, which meant that some Racket installations would support them, > and some would not. > > Since zo files are meant to be portable, they could not contain > single-precision floats. So, compilation would promote single literals > to doubles. > > This meant that compilation could change the behavior of a program. > ... > The solution we picked was to support single-precision floats by default > and to allow them in zos, which makes these discrepancies go away. > > I agree that having to handle single floats when reasoning about numbers > complicates things, and it annoys me too. But I still think it's less > problematic than what I describe above. Would it be even less problematic to get rid of them entirely, except in FFI? Stephen Bloch sbl...@adelphi.edu _ Racket Developers list: http://lists.racket-lang.org/dev
Re: [racket-dev] What are single flonums good for?
Single-precision float support used to be enabled via a configure option, which meant that some Racket installations would support them, and some would not. Since zo files are meant to be portable, they could not contain single-precision floats. So, compilation would promote single literals to doubles. This meant that compilation could change the behavior of a program. Here's an example: stamourv@ahuntsic:small-float-test$ cat test2.rkt #lang racket (define (f x) (displayln (flonum? x))) (f (if (with-input-from-string "#t" read) 1.0f0 2.0f0)) stamourv@ahuntsic:small-float-test$ racket test2.rkt #f stamourv@ahuntsic:small-float-test$ raco make test2.rkt stamourv@ahuntsic:small-float-test$ racket test2.rkt #t stamourv@ahuntsic:small-float-test$ This example has to be a bit convoluted to defeat constant folding, which makes the problem disappear: stamourv@ahuntsic:small-float-test$ cat test.rkt #lang racket (flonum? 1.0f0) stamourv@ahuntsic:small-float-test$ racket test.rkt #f stamourv@ahuntsic:small-float-test$ raco make test.rkt stamourv@ahuntsic:small-float-test$ racket test.rkt #f stamourv@ahuntsic:small-float-test$ raco decompile test.rkt (begin (module test (#%apply-values |_print-values@(lib "racket/private/modbeg.rkt")| '#f))) stamourv@ahuntsic:small-float-test$ This can make for pretty elusive bugs. This gets especially problematic when you add unsafe float operations to the mix, which can turn these issues into segfaults. The solution we picked was to support single-precision floats by default and to allow them in zos, which makes these discrepancies go away. I agree that having to handle single floats when reasoning about numbers complicates things, and it annoys me too. But I still think it's less problematic than what I describe above. At Wed, 12 Sep 2012 08:31:29 -0600, Neil Toronto wrote: > > I ask because I'm tired of worrying about them. More precisely, I'm > tired of Typed Racket (rightly) making me worry about them. > > I'm also a little bit tired of this: > > (: foo (case-> (Single-Flonum -> Single-Flonum) > (Flonum -> Flonum) > (Real -> Real))) > (define (foo x) >(cond [(double-flonum? x) (flfoo x)] > [(single-flonum? x) (real->single-flonum >(flfoo (real->double-flonum x)))] > [else (flfoo (real->double-flonum x))])) This function already converts rationals to doubles, and it seems `flfoo' produces doubles too. You could drop the second clause, always produce doubles, change the type to `(Real -> Flonum)' and leave the conversion to single to the client. Since the math library always operates on doubles internally anyway, this would also eliminate unnecessary conversions to singles between stages of a pipeline. > They make it easy to write wrong code, because it's easy to use > `exact->inexact' when you really should use `real->double-flonum'. Plot, > for example, fails to render functions that return single flonums. I'm > surprised it doesn't segfault. Good point, that's a problem. > I'm sure plot isn't the only one. Every use of `exact->inexact' in the > standard library is suspect. If followed by applying an unsafe op, it's > wrong. > > Why do we have these things? I don't know why they were added originally (as an option). In my limited experience, I don't think I've seen non-test code that uses them. Vincent _ Racket Developers list: http://lists.racket-lang.org/dev
[racket-dev] What are single flonums good for?
I ask because I'm tired of worrying about them. More precisely, I'm tired of Typed Racket (rightly) making me worry about them. I'm also a little bit tired of this: (: foo (case-> (Single-Flonum -> Single-Flonum) (Flonum -> Flonum) (Real -> Real))) (define (foo x) (cond [(double-flonum? x) (flfoo x)] [(single-flonum? x) (real->single-flonum (flfoo (real->double-flonum x)))] [else (flfoo (real->double-flonum x))])) I'm annoyed by the prospect of doing something similar to subtypes of Real-Distribution. It's nice right now that a probability is always a Flonum. Changing it would make things slower, more complicated, and more error-prone. They can't be for speed. I just ran some tests. With TR's optimizer off or in untyped Racket, the performance gain using single flonums is negligible. With TR's optimizer on, doubles are at least twice as fast. Compatibility with old code? No, they were enabled in 5.1.1. Compatibility with C code? Why not have the FFI convert them? Save space? I can see that. It won't help much if they're sent to math library functions, though. Those will convert them to flonums and usually box the converted values. They make it easy to write wrong code, because it's easy to use `exact->inexact' when you really should use `real->double-flonum'. Plot, for example, fails to render functions that return single flonums. I'm surprised it doesn't segfault. I'm sure plot isn't the only one. Every use of `exact->inexact' in the standard library is suspect. If followed by applying an unsafe op, it's wrong. Why do we have these things? Neil ⊥ _ Racket Developers list: http://lists.racket-lang.org/dev