implementing real (floating point) number comparison tolerance as a compiler directive.


(Ted van Gaalen) #1

in relation to my message about handling floating point number comparisation tolerance in e.g. a .stride function, wouldn't this be better handled by a compiler directive?

For example:

    @floatingPointComparisonTolerance = 0.001
     // all source that follows this will be compiled with this value
     // until reset or another value is specified with this directive.

    if fp1 == fp2 // will be evaluated with the above specified tolerance.

    for v in minival.stride(to: maxival, by: 0.1)

    for e from -1.0 to 123.45 by 0.1 // also in loops of course, as here in the for loop variant I will propose.

    @resetFloatingPointComparisonTolerance()

At any time, you should be able to change @floatingPointComparisonTolerance,
which will have its effect on source lines that follow it.

TedvG


(Joe Groff) #2

"Floats are inaccurate, let's just add random tolerances in" is a naive outlook on floating-point numerics. There are invariants which carefully-written floating point code can expect to hold in a lot of cases. We could provide tolerant comparison operations, but global state would be a poor way of doing so, and imposing this behavior on the standard comparison operators would be problematic. It'd be better to provide methods IMO, so that e.g. `fp1.equals(fp2, tolerance: 0x1p-44)` performed a comparison with a proportional tolerance check.

-Joe

···

On Mar 1, 2016, at 10:28 AM, ted van gaalen via swift-evolution <swift-evolution@swift.org> wrote:

in relation to my message about handling floating point number comparisation tolerance in e.g. a .stride function, wouldn't this be better handled by a compiler directive?

For example:

   @floatingPointComparisonTolerance = 0.001
    // all source that follows this will be compiled with this value
    // until reset or another value is specified with this directive.

   if fp1 == fp2 // will be evaluated with the above specified tolerance.

   for v in minival.stride(to: maxival, by: 0.1)

   for e from -1.0 to 123.45 by 0.1 // also in loops of course, as here in the for loop variant I will propose.

   @resetFloatingPointComparisonTolerance()

At any time, you should be able to change @floatingPointComparisonTolerance,
which will have its effect on source lines that follow it.


(Pyry Jahkola) #3

I don't think it's a good idea. That directive would break the transitivity requirement of Equatable (the last line below):

    /// **Equality is an equivalence relation**
    ///
    /// - `x == x` is `true`
    /// - `x == y` implies `y == x`
    /// - `x == y` and `y == z` implies `x == z`

You might want to define another operator or function for approximately equal instead.

(Not like equality wasn't already broken for floats because of NaN, but at least we can try to keep the remaining semantics sane.)

— Pyry

···

On 01 Mar 2016, at 20:28, ted van gaalen via swift-evolution <swift-evolution@swift.org> wrote:

in relation to my message about handling floating point number comparisation tolerance in e.g. a .stride function, wouldn't this be better handled by a compiler directive?

For example:

   @floatingPointComparisonTolerance = 0.001


(Ted van Gaalen) #4

They are not random tolerances and also not global as one
can set a specific (fine tuned) tolerance bandwidth for 1 or more
statements, following such a directive, until another, or a reset.
e.g.
    @floatingPointComparisonTolerance = 0.001 //tuned for a specific situation.

     if a == b {} // this statement is affected..
         
      If c != d {} // ..and also this one.
     @resetFloatingPointComparisonTolerance // default is none
     if a == b // here, no longer a tolerance band is active.
     
So, it is not global, but only in effect for statements in between/after these directives.

Nothing new here. Comparison tolerance has been in use in e.g. APL since ca 1975, see here for a good explanation.

http://microapl.com/apl_help/ch_020_070_150.htm

kind regards
TedvG

ted van gaalen

···

On 01 Mar 2016, at 21:00, Joe Groff <jgroff@apple.com> wrote:

On Mar 1, 2016, at 10:28 AM, ted van gaalen via swift-evolution <swift-evolution@swift.org> wrote:

in relation to my message about handling floating point number comparisation tolerance in e.g. a .stride function, wouldn't this be better handled by a compiler directive?

For example:

  @floatingPointComparisonTolerance = 0.001
   // all source that follows this will be compiled with this value
   // until reset or another value is specified with this directive.

  if fp1 == fp2 // will be evaluated with the above specified tolerance.

  for v in minival.stride(to: maxival, by: 0.1)

  for e from -1.0 to 123.45 by 0.1 // also in loops of course, as here in the for loop variant I will propose.

  @resetFloatingPointComparisonTolerance()

At any time, you should be able to change @floatingPointComparisonTolerance,
which will have its effect on source lines that follow it.

"Floats are inaccurate, let's just add random tolerances in" is a naive outlook on floating-point numerics. There are invariants which carefully-written floating point code can expect to hold in a lot of cases. We could provide tolerant comparison operations, but global state would be a poor way of doing so, and imposing this behavior on the standard comparison operators would be problematic. It'd be better to provide methods IMO, so that e.g. `fp1.equals(fp2, tolerance: 0x1p-44)` performed a comparison with a proportional tolerance check.

-Joe


(David Sweeris) #5

What about this?
infix operator ≈ {precedence 255}
func ≈ (value: Double, tolerance: Double) -> (value: Double, tolerance: Double) {
    return (value: value, tolerance: tolerance)
}
func == (lhs: Double, rhs: (value: Double, tolerance: Double)) -> Bool {
    return ((rhs.value - rhs.tolerance)...(rhs.value + rhs.tolerance)) ~= lhs
}
3.0 == 3.01 ≈ 0.001 // false
3.0 == 3.01 ≈ 0.01 // true

I tried using "ε", which is the standard symbol for "error", but that doesn't seem to be a valid operator character. "≈" (⌥-x, at least on a mac) is the only other one that seemed to make sense, with the possible exception of "∂", but I don't think that's as well-known.

- Dave Sweeris

···

Sent from my iPhone

On Mar 1, 2016, at 14:00, Joe Groff via swift-evolution <swift-evolution@swift.org> wrote:

On Mar 1, 2016, at 10:28 AM, ted van gaalen via swift-evolution <swift-evolution@swift.org> wrote:

in relation to my message about handling floating point number comparisation tolerance in e.g. a .stride function, wouldn't this be better handled by a compiler directive?

For example:

@floatingPointComparisonTolerance = 0.001
  // all source that follows this will be compiled with this value
  // until reset or another value is specified with this directive.

if fp1 == fp2 // will be evaluated with the above specified tolerance.

for v in minival.stride(to: maxival, by: 0.1)

for e from -1.0 to 123.45 by 0.1 // also in loops of course, as here in the for loop variant I will propose.

@resetFloatingPointComparisonTolerance()

At any time, you should be able to change @floatingPointComparisonTolerance,
which will have its effect on source lines that follow it.

"Floats are inaccurate, let's just add random tolerances in" is a naive outlook on floating-point numerics. There are invariants which carefully-written floating point code can expect to hold in a lot of cases. We could provide tolerant comparison operations, but global state would be a poor way of doing so, and imposing this behavior on the standard comparison operators would be problematic. It'd be better to provide methods IMO, so that e.g. `fp1.equals(fp2, tolerance: 0x1p-44)` performed a comparison with a proportional tolerance check.

-Joe
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Tino) #6

I hope that I'll finally have the time to write a pitch for "inheritance for structs" this weekend — this looks like another good use case for a "newtype" feature:

struct Length: Double {
  static let tolerance: Double = 0.001
}

override func ==(a: Length, b: Length) -> Bool {
  return (a - b).abs() < Length.tolerance
}

Of course, this example leaves many questions, but I hope the principle is clear.

Tino


(Joe Groff) #7

They are not random tolerances and also not global as one
can set a specific (fine tuned) tolerance bandwidth for 1 or more
statements, following such a directive, until another, or a reset.
e.g.
    @floatingPointComparisonTolerance = 0.001 //tuned for a specific situation.

     if a == b {} // this statement is affected..
         
      If c != d {} // ..and also this one.
     @resetFloatingPointComparisonTolerance // default is none
     if a == b // here, no longer a tolerance band is active.
     
So, it is not global, but only in effect for statements in between/after these directives.

If we literally follow the APL model, then the tolerance is global state that nonlocally changes the behavior of every operation. We don't do this kind of implicit parameterization anywhere else, and similar features have proven to be brittle to use in practice (see also, for instance, the ability for Perl and some BASIC languages to dynamically set the array index base to 0 or 1, catastrophically breaking any code you call into that expects the other base).

-Joe

···

On Mar 1, 2016, at 3:44 PM, ted van gaalen <tedvgiosdev@gmail.com> wrote:

Nothing new here. Comparison tolerance has been in use in e.g. APL since ca 1975, see here for a good explanation.

http://microapl.com/apl_help/ch_020_070_150.htm


(Ted van Gaalen) #8

? I don't see transivity requirement broken here, because -within a comparison tolerance- they still are true.

ted van gaalen it services

Professional App development for
Apple IOS, Windows & Android
tablets and mobile phones
based on > 30 yrs of IT experience.
Web design & programming.
IBM Mainframe application programming.

www.tedvg.com

Ted F.A. van Gaalen

Hauptstr. 19/3
D-88636 Illmensee
Germany
T: 49 7558 92 17 840
M: 49 174 7707 422

···

On 01 Mar 2016, at 20:39, Pyry Jahkola <pyry.jahkola@iki.fi> wrote:

On 01 Mar 2016, at 20:28, ted van gaalen via swift-evolution <swift-evolution@swift.org> wrote:

in relation to my message about handling floating point number comparisation tolerance in e.g. a .stride function, wouldn't this be better handled by a compiler directive?

For example:

   @floatingPointComparisonTolerance = 0.001

I don't think it's a good idea. That directive would break the transitivity requirement of Equatable (the last line below):

    /// **Equality is an equivalence relation**
    ///
    /// - `x == x` is `true`
    /// - `x == y` implies `y == x`
    /// - `x == y` and `y == z` implies `x == z`

You might want to define another operator or function for approximately equal instead.

(Not like equality wasn't already broken for floats because of NaN, but at least we can try to keep the remaining semantics sane.)

— Pyry


(Ted van Gaalen) #9

Yes, in APL it is global, but not in what I propose for Swift here.

ted van gaalen

···

On 02 Mar 2016, at 00:48, Joe Groff <jgroff@apple.com> wrote:

On Mar 1, 2016, at 3:44 PM, ted van gaalen <tedvgiosdev@gmail.com> wrote:

They are not random tolerances and also not global as one
can set a specific (fine tuned) tolerance bandwidth for 1 or more
statements, following such a directive, until another, or a reset.
e.g.
    @floatingPointComparisonTolerance = 0.001 //tuned for a specific situation.

     if a == b {} // this statement is affected..
         
      If c != d {} // ..and also this one.
     @resetFloatingPointComparisonTolerance // default is none
     if a == b // here, no longer a tolerance band is active.
     
So, it is not global, but only in effect for statements in between/after these directives.

If we literally follow the APL model, then the tolerance is global state that nonlocally changes the behavior of every operation. We don't do this kind of implicit parameterization anywhere else, and similar features have proven to be brittle to use in practice (see also, for instance, the ability for Perl and some BASIC languages to dynamically set the array index base to 0 or 1, catastrophically breaking any code you call into that expects the other base).

-Joe

Nothing new here. Comparison tolerance has been in use in e.g. APL since ca 1975, see here for a good explanation.

http://microapl.com/apl_help/ch_020_070_150.htm


(Joe Groff) #10

That's cute. In a real implementation of tolerant comparison, you'd want to scale the tolerance to the magnitude of the larger operand, though. (See http://code.jsoftware.com/wiki/Essays/Tolerant_Comparison .)

-Joe

···

On Mar 2, 2016, at 12:45 PM, David Sweeris <davesweeris@mac.com> wrote:

func == (lhs: Double, rhs: (value: Double, tolerance: Double)) -> Bool {
    return ((rhs.value - rhs.tolerance)...(rhs.value + rhs.tolerance)) ~= lhs
}
3.0 == 3.01 ≈ 0.001 // false
3.0 == 3.01 ≈ 0.01 // true

I tried using "ε", which is the standard symbol for "error", but that doesn't seem to be a valid operator character. "≈" (⌥-x, at least on a mac) is the only other one that seemed to make sense, with the possible exception of "∂", but I don't think that's as well-known.


(Joe Groff) #11

This is also a place where function partial application might be interesting:

func equalityWithTolerance(tolerance: Double) -> (Double, Double) -> Bool {
  return {
    var exp0 = 0, exp1 = 0
    frexp($0, &exp0)
    frexp($1, &exp1)
    return abs($0 - $1) < scalb(tolerance, max(exp0, exp1))
  }
}

If you could locally bind operators, you could then do this:

func compareLengths(x: Double, y: Double) -> Bool {
  let (==) = equalityWithTolerance(0x1p-44)
  return x == y // Uses local (==)
}

-Joe

···

On Mar 2, 2016, at 1:23 PM, Tino Heth via swift-evolution <swift-evolution@swift.org> wrote:

I hope that I'll finally have the time to write a pitch for "inheritance for structs" this weekend — this looks like another good use case for a "newtype" feature:

struct Length: Double {
  static let tolerance: Double = 0.001
}

override func ==(a: Length, b: Length) -> Bool {
  return (a - b).abs() < Length.tolerance
}

Of course, this example leaves many questions, but I hope the principle is clear.


(David Sweeris) #12

K… Does replacing my cute == function with one that accounts for everything in that link (or at least a sufficiently large subset of it) solve the problem?

···

On Mar 2, 2016, at 2:56 PM, Joe Groff <jgroff@apple.com> wrote:

On Mar 2, 2016, at 12:45 PM, David Sweeris <davesweeris@mac.com <mailto:davesweeris@mac.com>> wrote:

func == (lhs: Double, rhs: (value: Double, tolerance: Double)) -> Bool {
    return ((rhs.value - rhs.tolerance)...(rhs.value + rhs.tolerance)) ~= lhs
}
3.0 == 3.01 ≈ 0.001 // false
3.0 == 3.01 ≈ 0.01 // true

I tried using "ε", which is the standard symbol for "error", but that doesn't seem to be a valid operator character. "≈" (⌥-x, at least on a mac) is the only other one that seemed to make sense, with the possible exception of "∂", but I don't think that's as well-known.

That's cute. In a real implementation of tolerant comparison, you'd want to scale the tolerance to the magnitude of the larger operand, though. (See http://code.jsoftware.com/wiki/Essays/Tolerant_Comparison .)

-Joe


(Ted van Gaalen) #13

Hi Joe,

to just fuzzy compare 2 floating point numbers,
the solution you describe uses
- 2 functions, with therein 6 calls to frexp, abs, max and scalb...
isn’t that overkill ?

I still think a compiler directive embedded in sources at desired locations as e.g.

@setFLoatingPointTolerance: 0.0001
    .
   if a == b
   ...
@setFloatingPointToleranceOff
   …
@setFLoatingPointTolerance: 0.04
    .
   if temperature == roomTemperature
   ...
@setFloatingPointToleranceOff

So every floating point compare in source between these directives will be
will be compiled differently.
Leave it to the compiler, so no special functions/ parameters are needed,
and would be far more efficient I think.

Kind Regards
TedvG

···

On 02.03.2016, at 22:28, Joe Groff <jgroff@apple.com> wrote:

On Mar 2, 2016, at 1:23 PM, Tino Heth via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I hope that I'll finally have the time to write a pitch for "inheritance for structs" this weekend — this looks like another good use case for a "newtype" feature:

struct Length: Double {
  static let tolerance: Double = 0.001
}

override func ==(a: Length, b: Length) -> Bool {
  return (a - b).abs() < Length.tolerance
}

Of course, this example leaves many questions, but I hope the principle is clear.

This is also a place where function partial application might be interesting:

func equalityWithTolerance(tolerance: Double) -> (Double, Double) -> Bool {
  return {
    var exp0 = 0, exp1 = 0
    frexp($0, &exp0)
    frexp($1, &exp1)
    return abs($0 - $1) < scalb(tolerance, max(exp0, exp1))
  }
}

If you could locally bind operators, you could then do this:

func compareLengths(x: Double, y: Double) -> Bool {
  let (==) = equalityWithTolerance(0x1p-44)
  return x == y // Uses local (==)
}

-Joe


(Pyry Jahkola) #14

? I don't see transivity requirement broken here, because -within a comparison tolerance- they still are true.

Consider:
    a = 1.0
    b = 1.0 + 0.75 * eps
    c = 1.0 + 1.5 * eps

Now,
    abs(a - b) < eps, so a ~ b, and
    abs(b - c) < eps, so b ~ c,

but abs(a - c) > eps, so a and c are "not close".


(Joe Groff) #15

K… Does replacing my cute == function with one that accounts for everything in that link (or at least a sufficiently large subset of it) solve the problem?

My vague preference is for named methods. In numerics-heavy domains I could see this being valuable enough to burn an operator on.

-Joe

···

On Mar 2, 2016, at 1:19 PM, davesweeris@mac.com wrote:

On Mar 2, 2016, at 2:56 PM, Joe Groff <jgroff@apple.com <mailto:jgroff@apple.com>> wrote:

On Mar 2, 2016, at 12:45 PM, David Sweeris <davesweeris@mac.com <mailto:davesweeris@mac.com>> wrote:

func == (lhs: Double, rhs: (value: Double, tolerance: Double)) -> Bool {
    return ((rhs.value - rhs.tolerance)...(rhs.value + rhs.tolerance)) ~= lhs
}
3.0 == 3.01 ≈ 0.001 // false
3.0 == 3.01 ≈ 0.01 // true

I tried using "ε", which is the standard symbol for "error", but that doesn't seem to be a valid operator character. "≈" (⌥-x, at least on a mac) is the only other one that seemed to make sense, with the possible exception of "∂", but I don't think that's as well-known.

That's cute. In a real implementation of tolerant comparison, you'd want to scale the tolerance to the magnitude of the larger operand, though. (See http://code.jsoftware.com/wiki/Essays/Tolerant_Comparison .)

-Joe


(Joe Groff) #16

Hi Joe,

to just fuzzy compare 2 floating point numbers,
the solution you describe uses
- 2 functions, with therein 6 calls to frexp, abs, max and scalb...
isn’t that overkill ?

That's how APL-style tolerance is defined—the tolerance is scaled to the greater exponent of the operands. frexp, scalb, and fabs all reduce to bitwise operations on the float representation, so this should be possible to compile down to something cheap (if LLVM can't do it natively, then by hand, at least).

I still think a compiler directive embedded in sources at desired locations as e.g.

@setFLoatingPointTolerance: 0.0001
    .
   if a == b
   ...
@setFloatingPointToleranceOff
   …
@setFLoatingPointTolerance: 0.04
    .
   if temperature == roomTemperature
   ...
@setFloatingPointToleranceOff

So every floating point compare in source between these directives will be
will be compiled differently.
Leave it to the compiler, so no special functions/ parameters are needed,
and would be far more efficient I think.

We don't do this anywhere else, and I'm not sure this narrow use case justifies such an invasive change to how functions work. There might be an interesting general purpose feature in supporting implicit context arguments (beyond the usual 'self' for methods).

-Joe

···

On Mar 4, 2016, at 5:11 AM, Ted F.A. van Gaalen <tedvgiosdev@gmail.com> wrote:


(Félix Cloutier) #17

Another problem that I perceive with the scoped approach (and global state) is that it can't reach inside C (or Objective-C) functions.

Félix

···

Le 4 mars 2016 à 12:53:28, Joe Groff via swift-evolution <swift-evolution@swift.org> a écrit :

On Mar 4, 2016, at 5:11 AM, Ted F.A. van Gaalen <tedvgiosdev@gmail.com> wrote:

Hi Joe,

to just fuzzy compare 2 floating point numbers,
the solution you describe uses
- 2 functions, with therein 6 calls to frexp, abs, max and scalb...
isn’t that overkill ?

That's how APL-style tolerance is defined—the tolerance is scaled to the greater exponent of the operands. frexp, scalb, and fabs all reduce to bitwise operations on the float representation, so this should be possible to compile down to something cheap (if LLVM can't do it natively, then by hand, at least).

I still think a compiler directive embedded in sources at desired locations as e.g.

@setFLoatingPointTolerance: 0.0001
   .
  if a == b
  ...
@setFloatingPointToleranceOff
  …
@setFLoatingPointTolerance: 0.04
   .
  if temperature == roomTemperature
  ...
@setFloatingPointToleranceOff

So every floating point compare in source between these directives will be
will be compiled differently.
Leave it to the compiler, so no special functions/ parameters are needed,
and would be far more efficient I think.

We don't do this anywhere else, and I'm not sure this narrow use case justifies such an invasive change to how functions work. There might be an interesting general purpose feature in supporting implicit context arguments (beyond the usual 'self' for methods).

-Joe

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Ted van Gaalen) #18

thanks, i see what you mean
Ted

···

On 04.03.2016, at 18:53, Joe Groff <jgroff@apple.com> wrote:

On Mar 4, 2016, at 5:11 AM, Ted F.A. van Gaalen <tedvgiosdev@gmail.com <mailto:tedvgiosdev@gmail.com>> wrote:

Hi Joe,

to just fuzzy compare 2 floating point numbers,
the solution you describe uses
- 2 functions, with therein 6 calls to frexp, abs, max and scalb...
isn’t that overkill ?

That's how APL-style tolerance is defined—the tolerance is scaled to the greater exponent of the operands. frexp, scalb, and fabs all reduce to bitwise operations on the float representation, so this should be possible to compile down to something cheap (if LLVM can't do it natively, then by hand, at least).

I still think a compiler directive embedded in sources at desired locations as e.g.

@setFLoatingPointTolerance: 0.0001
   .
  if a == b
  ...
@setFloatingPointToleranceOff
  …
@setFLoatingPointTolerance: 0.04
   .
  if temperature == roomTemperature
  ...
@setFloatingPointToleranceOff

So every floating point compare in source between these directives will be
will be compiled differently.
Leave it to the compiler, so no special functions/ parameters are needed,
and would be far more efficient I think.

We don't do this anywhere else, and I'm not sure this narrow use case justifies such an invasive change to how functions work. There might be an interesting general purpose feature in supporting implicit context arguments (beyond the usual 'self' for methods).

-Joe


(Ted van Gaalen) #19

? but it should only work on the source it compiles, not on what’s called.
TedvG

···

On 04.03.2016, at 19:22, Félix Cloutier <felixcca@yahoo.ca> wrote:

Another problem that I perceive with the scoped approach (and global state) is that it can't reach inside C (or Objective-C) functions.

Félix

Le 4 mars 2016 à 12:53:28, Joe Groff via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> a écrit :

On Mar 4, 2016, at 5:11 AM, Ted F.A. van Gaalen <tedvgiosdev@gmail.com <mailto:tedvgiosdev@gmail.com>> wrote:

Hi Joe,

to just fuzzy compare 2 floating point numbers,
the solution you describe uses
- 2 functions, with therein 6 calls to frexp, abs, max and scalb...
isn’t that overkill ?

That's how APL-style tolerance is defined—the tolerance is scaled to the greater exponent of the operands. frexp, scalb, and fabs all reduce to bitwise operations on the float representation, so this should be possible to compile down to something cheap (if LLVM can't do it natively, then by hand, at least).

I still think a compiler directive embedded in sources at desired locations as e.g.

@setFLoatingPointTolerance: 0.0001
   .
  if a == b
  ...
@setFloatingPointToleranceOff
  …
@setFLoatingPointTolerance: 0.04
   .
  if temperature == roomTemperature
  ...
@setFloatingPointToleranceOff

So every floating point compare in source between these directives will be
will be compiled differently.
Leave it to the compiler, so no special functions/ parameters are needed,
and would be far more efficient I think.

We don't do this anywhere else, and I'm not sure this narrow use case justifies such an invasive change to how functions work. There might be an interesting general purpose feature in supporting implicit context arguments (beyond the usual 'self' for methods).

-Joe

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution


(Stephen Canon) #20

In particular, if you could effect how equality is defined for callee functions, you would break a lot of library code that expects equality to really be exact equality. There are a wide variety of reasons for doing this in mathematical library code (zero as a sentinel value, working around singularities that really only effect a single value, etc). Any approach to approximate equality that escapes scope would be a source of extremely hard-to-diagnose bugs.

– Steve

···

On Mar 4, 2016, at 10:28 AM, Ted F.A. van Gaalen via swift-evolution <swift-evolution@swift.org> wrote:

  ? but it should only work on the source it compiles, not on what’s called.
TedvG

On 04.03.2016, at 19:22, Félix Cloutier <felixcca@yahoo.ca <mailto:felixcca@yahoo.ca>> wrote:

Another problem that I perceive with the scoped approach (and global state) is that it can't reach inside C (or Objective-C) functions.

Félix

Le 4 mars 2016 à 12:53:28, Joe Groff via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> a écrit :

On Mar 4, 2016, at 5:11 AM, Ted F.A. van Gaalen <tedvgiosdev@gmail.com <mailto:tedvgiosdev@gmail.com>> wrote:

Hi Joe,

to just fuzzy compare 2 floating point numbers,
the solution you describe uses
- 2 functions, with therein 6 calls to frexp, abs, max and scalb...
isn’t that overkill ?

That's how APL-style tolerance is defined—the tolerance is scaled to the greater exponent of the operands. frexp, scalb, and fabs all reduce to bitwise operations on the float representation, so this should be possible to compile down to something cheap (if LLVM can't do it natively, then by hand, at least).

I still think a compiler directive embedded in sources at desired locations as e.g.

@setFLoatingPointTolerance: 0.0001
   .
  if a == b
  ...
@setFloatingPointToleranceOff
  …
@setFLoatingPointTolerance: 0.04
   .
  if temperature == roomTemperature
  ...
@setFloatingPointToleranceOff

So every floating point compare in source between these directives will be
will be compiled differently.
Leave it to the compiler, so no special functions/ parameters are needed,
and would be far more efficient I think.

We don't do this anywhere else, and I'm not sure this narrow use case justifies such an invasive change to how functions work. There might be an interesting general purpose feature in supporting implicit context arguments (beyond the usual 'self' for methods).

-Joe

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution