[racket-dev] What are single flonums good for?

2012-09-12 Thread Neil Toronto
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


Re: [racket-dev] What are single flonums good for?

2012-09-12 Thread Vincent St-Amour
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


Re: [racket-dev] What are single flonums good for?

2012-09-12 Thread Stephen Bloch

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?

2012-09-12 Thread Neil Toronto

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?

2012-09-12 Thread Eli Barzilay
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?

2012-09-12 Thread Robby Findler
On Wed, Sep 12, 2012 at 11:24 AM, Vincent St-Amour stamo...@ccs.neu.edu 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?

2012-09-12 Thread Jay McCarthy
On Wed, Sep 12, 2012 at 8:31 AM, Neil Toronto neil.toro...@gmail.com 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 j...@cs.byu.edu
Assistant Professor / Brigham Young University
http://faculty.cs.byu.edu/~jay

The glory of God is Intelligence - DC 93
_
  Racket Developers list:
  http://lists.racket-lang.org/dev


Re: [racket-dev] What are single flonums good for?

2012-09-12 Thread Robby Findler
On Wed, Sep 12, 2012 at 3:47 PM, Matthew Flatt mfl...@cs.utah.edu 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