Why are BinaryFloatingPoint's RawSignificand and RawExponent different type?


(Jens Persson) #1

I can understand why
Double.RawSignificand is UInt64
and
Float.RawSignificand is UInt32

But I can't understand why both
Double.RawExponent
and
Float.RawExponent
should be UInt.

Why aren't they also just UInt64 and UInt32, resp.?

/Jens


(Stephen Canon) #2

Let me flip the question: why would they be UInt64 and UInt32? Absent a reason to prefer a specific fixed-with type, Swift integers should generally default to being [U]Int (and ideally Int, but RawExponent is Unsigned).

– Steve

···

On Aug 26, 2016, at 6:06 PM, Jens Persson via swift-dev <swift-dev@swift.org> wrote:

I can understand why
Double.RawSignificand is UInt64
and
Float.RawSignificand is UInt32

But I can't understand why both
Double.RawExponent
and
Float.RawExponent
should be UInt.

Why aren't they also just UInt64 and UInt32, resp.?


(Jens Persson) #3

Reason for asking is that I have this:

extension Double {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        let bitPattern = s | (1023 << 52)
        self = unsafeBitCast(bitPattern, to: Double.self) - 1.0
    }
}
extension Float {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        let bitPattern = s | (127 << 23)
        self = unsafeBitCast(bitPattern, to: Float.self) - 1.0
    }
}

But they would be better as:
extension BinaryFloatingPoint {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        ... problems here, have to try casting things into RawSignificand's
type ...
    }
}

Please have a go at that and perhaps you see what I mean or you will come
up with a nice solution that I have missed. (Speed is very important btw.)

/Jens

···

On Sat, Aug 27, 2016 at 1:02 AM, Stephen Canon <scanon@apple.com> wrote:

> On Aug 26, 2016, at 6:06 PM, Jens Persson via swift-dev < > swift-dev@swift.org> wrote:
>
> I can understand why
> Double.RawSignificand is UInt64
> and
> Float.RawSignificand is UInt32
>
> But I can't understand why both
> Double.RawExponent
> and
> Float.RawExponent
> should be UInt.
>
> Why aren't they also just UInt64 and UInt32, resp.?

Let me flip the question: why would they be UInt64 and UInt32? Absent a
reason to prefer a specific fixed-with type, Swift integers should
generally default to being [U]Int (and ideally Int, but RawExponent is
Unsigned).

– Steve


(Jens Persson) #4

Oh, to more directly answer your question: I don't like having to create a
UInt (UInt64) value when all my bit manipulaton code happens in UInt32 (for
Float) for example.

The most probable context for using these computed properties and types of
BinaryFloatingPoint is one in which specific fixed width types really
matters a lot (look at the name of the protocol and the properties and
assocated types we are talking about).

/Jens

···

On Sat, Aug 27, 2016 at 1:15 AM, Jens Persson <jens@bitcycle.com> wrote:

Reason for asking is that I have this:

extension Double {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        let bitPattern = s | (1023 << 52)
        self = unsafeBitCast(bitPattern, to: Double.self) - 1.0
    }
}
extension Float {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        let bitPattern = s | (127 << 23)
        self = unsafeBitCast(bitPattern, to: Float.self) - 1.0
    }
}

But they would be better as:
extension BinaryFloatingPoint {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        ... problems here, have to try casting things into
RawSignificand's type ...
    }
}

Please have a go at that and perhaps you see what I mean or you will come
up with a nice solution that I have missed. (Speed is very important btw.)

/Jens

On Sat, Aug 27, 2016 at 1:02 AM, Stephen Canon <scanon@apple.com> wrote:

> On Aug 26, 2016, at 6:06 PM, Jens Persson via swift-dev < >> swift-dev@swift.org> wrote:
>
> I can understand why
> Double.RawSignificand is UInt64
> and
> Float.RawSignificand is UInt32
>
> But I can't understand why both
> Double.RawExponent
> and
> Float.RawExponent
> should be UInt.
>
> Why aren't they also just UInt64 and UInt32, resp.?

Let me flip the question: why would they be UInt64 and UInt32? Absent a
reason to prefer a specific fixed-with type, Swift integers should
generally default to being [U]Int (and ideally Int, but RawExponent is
Unsigned).

– Steve


(Stephen Canon) #5

This doesn’t really scale up very well, though. BinaryFloatingPoint needs to also be able to model e.g. Float2048 or similar; we generally don't want to require that RawExponent to be the same type as RawSignificand (which I think is what you’re really suggesting), because in typical bignum usage significands are much larger than exponents.

It sounds like maybe you actually want to be operating directly on bitPatterns, rather than the abstract fields of the types.

– Steve

···

On Aug 26, 2016, at 7:21 PM, Jens Persson <jens@bitcycle.com> wrote:

Oh, to more directly answer your question: I don't like having to create a UInt (UInt64) value when all my bit manipulaton code happens in UInt32 (for Float) for example.

The most probable context for using these computed properties and types of BinaryFloatingPoint is one in which specific fixed width types really matters a lot (look at the name of the protocol and the properties and assocated types we are talking about).

/Jens

On Sat, Aug 27, 2016 at 1:15 AM, Jens Persson <jens@bitcycle.com <mailto:jens@bitcycle.com>> wrote:
Reason for asking is that I have this:

extension Double {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        let bitPattern = s | (1023 << 52)
        self = unsafeBitCast(bitPattern, to: Double.self) - 1.0
    }
}
extension Float {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        let bitPattern = s | (127 << 23)
        self = unsafeBitCast(bitPattern, to: Float.self) - 1.0
    }
}

But they would be better as:
extension BinaryFloatingPoint {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        ... problems here, have to try casting things into RawSignificand's type ...
    }
}

Please have a go at that and perhaps you see what I mean or you will come up with a nice solution that I have missed. (Speed is very important btw.)

/Jens

On Sat, Aug 27, 2016 at 1:02 AM, Stephen Canon <scanon@apple.com <mailto:scanon@apple.com>> wrote:
> On Aug 26, 2016, at 6:06 PM, Jens Persson via swift-dev <swift-dev@swift.org <mailto:swift-dev@swift.org>> wrote:
>
> I can understand why
> Double.RawSignificand is UInt64
> and
> Float.RawSignificand is UInt32
>
> But I can't understand why both
> Double.RawExponent
> and
> Float.RawExponent
> should be UInt.
>
> Why aren't they also just UInt64 and UInt32, resp.?

Let me flip the question: why would they be UInt64 and UInt32? Absent a reason to prefer a specific fixed-with type, Swift integers should generally default to being [U]Int (and ideally Int, but RawExponent is Unsigned).

– Steve


(Jens Persson) #6

I understand.
It's just very tempting to try and use the new static computed properties
for eg 23 and 52 etc.
I guess I'll just have to write a lot of boilerplate, or perhaps a protocol
that is just implemented by Double and Float (that will be very similar to
BinaryFloatingPoint in a lot of ways).
/Jens

···

On Sat, Aug 27, 2016 at 1:25 AM, Stephen Canon <scanon@apple.com> wrote:

This doesn’t really scale up very well, though. BinaryFloatingPoint needs
to also be able to model e.g. Float2048 or similar; we generally don't want
to require that RawExponent to be the same type as RawSignificand (which I
think is what you’re really suggesting), because in typical bignum usage
significands are much larger than exponents.

It sounds like maybe you actually want to be operating directly on
bitPatterns, rather than the abstract fields of the types.

– Steve

On Aug 26, 2016, at 7:21 PM, Jens Persson <jens@bitcycle.com> wrote:

Oh, to more directly answer your question: I don't like having to create a
UInt (UInt64) value when all my bit manipulaton code happens in UInt32 (for
Float) for example.

The most probable context for using these computed properties and types of
BinaryFloatingPoint is one in which specific fixed width types really
matters a lot (look at the name of the protocol and the properties and
assocated types we are talking about).

/Jens

On Sat, Aug 27, 2016 at 1:15 AM, Jens Persson <jens@bitcycle.com> wrote:

Reason for asking is that I have this:

extension Double {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        let bitPattern = s | (1023 << 52)
        self = unsafeBitCast(bitPattern, to: Double.self) - 1.0
    }
}
extension Float {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        let bitPattern = s | (127 << 23)
        self = unsafeBitCast(bitPattern, to: Float.self) - 1.0
    }
}

But they would be better as:
extension BinaryFloatingPoint {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        ... problems here, have to try casting things into
RawSignificand's type ...
    }
}

Please have a go at that and perhaps you see what I mean or you will come
up with a nice solution that I have missed. (Speed is very important btw.)

/Jens

On Sat, Aug 27, 2016 at 1:02 AM, Stephen Canon <scanon@apple.com> wrote:

> On Aug 26, 2016, at 6:06 PM, Jens Persson via swift-dev < >>> swift-dev@swift.org> wrote:
>
> I can understand why
> Double.RawSignificand is UInt64
> and
> Float.RawSignificand is UInt32
>
> But I can't understand why both
> Double.RawExponent
> and
> Float.RawExponent
> should be UInt.
>
> Why aren't they also just UInt64 and UInt32, resp.?

Let me flip the question: why would they be UInt64 and UInt32? Absent a
reason to prefer a specific fixed-with type, Swift integers should
generally default to being [U]Int (and ideally Int, but RawExponent is
Unsigned).

– Steve


(Stephen Canon) #7

Where does your RawSignificand input come from? Is that really the type that you want?

I don’t think you really need very much boilerplate at all here.

···

On Aug 26, 2016, at 7:30 PM, Jens Persson <jens@bitcycle.com> wrote:

I understand.
It's just very tempting to try and use the new static computed properties for eg 23 and 52 etc.
I guess I'll just have to write a lot of boilerplate, or perhaps a protocol that is just implemented by Double and Float (that will be very similar to BinaryFloatingPoint in a lot of ways).
/Jens

On Sat, Aug 27, 2016 at 1:25 AM, Stephen Canon <scanon@apple.com <mailto:scanon@apple.com>> wrote:
This doesn’t really scale up very well, though. BinaryFloatingPoint needs to also be able to model e.g. Float2048 or similar; we generally don't want to require that RawExponent to be the same type as RawSignificand (which I think is what you’re really suggesting), because in typical bignum usage significands are much larger than exponents.

It sounds like maybe you actually want to be operating directly on bitPatterns, rather than the abstract fields of the types.

– Steve

On Aug 26, 2016, at 7:21 PM, Jens Persson <jens@bitcycle.com <mailto:jens@bitcycle.com>> wrote:

Oh, to more directly answer your question: I don't like having to create a UInt (UInt64) value when all my bit manipulaton code happens in UInt32 (for Float) for example.

The most probable context for using these computed properties and types of BinaryFloatingPoint is one in which specific fixed width types really matters a lot (look at the name of the protocol and the properties and assocated types we are talking about).

/Jens

On Sat, Aug 27, 2016 at 1:15 AM, Jens Persson <jens@bitcycle.com <mailto:jens@bitcycle.com>> wrote:
Reason for asking is that I have this:

extension Double {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        let bitPattern = s | (1023 << 52)
        self = unsafeBitCast(bitPattern, to: Double.self) - 1.0
    }
}
extension Float {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        let bitPattern = s | (127 << 23)
        self = unsafeBitCast(bitPattern, to: Float.self) - 1.0
    }
}

But they would be better as:
extension BinaryFloatingPoint {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        ... problems here, have to try casting things into RawSignificand's type ...
    }
}

Please have a go at that and perhaps you see what I mean or you will come up with a nice solution that I have missed. (Speed is very important btw.)

/Jens

On Sat, Aug 27, 2016 at 1:02 AM, Stephen Canon <scanon@apple.com <mailto:scanon@apple.com>> wrote:
> On Aug 26, 2016, at 6:06 PM, Jens Persson via swift-dev <swift-dev@swift.org <mailto:swift-dev@swift.org>> wrote:
>
> I can understand why
> Double.RawSignificand is UInt64
> and
> Float.RawSignificand is UInt32
>
> But I can't understand why both
> Double.RawExponent
> and
> Float.RawExponent
> should be UInt.
>
> Why aren't they also just UInt64 and UInt32, resp.?

Let me flip the question: why would they be UInt64 and UInt32? Absent a reason to prefer a specific fixed-with type, Swift integers should generally default to being [U]Int (and ideally Int, but RawExponent is Unsigned).

– Steve


(Stephen Canon) #8

Assuming RawSignificand really is the type you want, I think this does what you’re looking for?

protocol BinaryFloatingPointWithBitPattern: BinaryFloatingPoint {
    init(bitPattern: RawSignificand)
    var bitPattern: RawSignificand { get }
}

extension Float: BinaryFloatingPointWithBitPattern { }
extension Double: BinaryFloatingPointWithBitPattern { }

extension BinaryFloatingPointWithBitPattern {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        self = Self(bitPattern: Self(1).bitPattern | s) - 1
    }
}

···

On Aug 26, 2016, at 7:38 PM, Stephen Canon via swift-dev <swift-dev@swift.org> wrote:

Where does your RawSignificand input come from? Is that really the type that you want?

I don’t think you really need very much boilerplate at all here.

On Aug 26, 2016, at 7:30 PM, Jens Persson <jens@bitcycle.com> wrote:

I understand.
It's just very tempting to try and use the new static computed properties for eg 23 and 52 etc.
I guess I'll just have to write a lot of boilerplate, or perhaps a protocol that is just implemented by Double and Float (that will be very similar to BinaryFloatingPoint in a lot of ways).
/Jens

On Sat, Aug 27, 2016 at 1:25 AM, Stephen Canon <scanon@apple.com> wrote:
This doesn’t really scale up very well, though. BinaryFloatingPoint needs to also be able to model e.g. Float2048 or similar; we generally don't want to require that RawExponent to be the same type as RawSignificand (which I think is what you’re really suggesting), because in typical bignum usage significands are much larger than exponents.

It sounds like maybe you actually want to be operating directly on bitPatterns, rather than the abstract fields of the types.

– Steve

On Aug 26, 2016, at 7:21 PM, Jens Persson <jens@bitcycle.com> wrote:

Oh, to more directly answer your question: I don't like having to create a UInt (UInt64) value when all my bit manipulaton code happens in UInt32 (for Float) for example.

The most probable context for using these computed properties and types of BinaryFloatingPoint is one in which specific fixed width types really matters a lot (look at the name of the protocol and the properties and assocated types we are talking about).

/Jens

On Sat, Aug 27, 2016 at 1:15 AM, Jens Persson <jens@bitcycle.com> wrote:
Reason for asking is that I have this:

extension Double {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        let bitPattern = s | (1023 << 52)
        self = unsafeBitCast(bitPattern, to: Double.self) - 1.0
    }
}
extension Float {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        let bitPattern = s | (127 << 23)
        self = unsafeBitCast(bitPattern, to: Float.self) - 1.0
    }
}

But they would be better as:
extension BinaryFloatingPoint {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        ... problems here, have to try casting things into RawSignificand's type ...
    }
}

Please have a go at that and perhaps you see what I mean or you will come up with a nice solution that I have missed. (Speed is very important btw.)

/Jens

On Sat, Aug 27, 2016 at 1:02 AM, Stephen Canon <scanon@apple.com> wrote:
> On Aug 26, 2016, at 6:06 PM, Jens Persson via swift-dev <swift-dev@swift.org> wrote:
>
> I can understand why
> Double.RawSignificand is UInt64
> and
> Float.RawSignificand is UInt32
>
> But I can't understand why both
> Double.RawExponent
> and
> Float.RawExponent
> should be UInt.
>
> Why aren't they also just UInt64 and UInt32, resp.?

Let me flip the question: why would they be UInt64 and UInt32? Absent a reason to prefer a specific fixed-with type, Swift integers should generally default to being [U]Int (and ideally Int, but RawExponent is Unsigned).

– Steve

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


(Stephen Canon) #9

If BinaryFloatingPoint had init(_: RawSignificand), you could also just write:

extension BinaryFloatingPoint {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        self = Self(s) * .ulpOfOne
    }
}

(this is why I ask if RawSignificand is really the type you want; if you use some concrete integer type this will work). But once we have all the new integer protocol conformances, we’ll have a generic init from any integer type (this was already reviewed for FloatingPoint, but isn’t implementable without the Integer support), which will also make this possible.

···

On Aug 26, 2016, at 7:47 PM, Stephen Canon via swift-dev <swift-dev@swift.org> wrote:

Assuming RawSignificand really is the type you want, I think this does what you’re looking for?

protocol BinaryFloatingPointWithBitPattern: BinaryFloatingPoint {
    init(bitPattern: RawSignificand)
    var bitPattern: RawSignificand { get }
}

extension Float: BinaryFloatingPointWithBitPattern { }
extension Double: BinaryFloatingPointWithBitPattern { }

extension BinaryFloatingPointWithBitPattern {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        self = Self(bitPattern: Self(1).bitPattern | s) - 1
    }
}

On Aug 26, 2016, at 7:38 PM, Stephen Canon via swift-dev <swift-dev@swift.org <mailto:swift-dev@swift.org>> wrote:

Where does your RawSignificand input come from? Is that really the type that you want?

I don’t think you really need very much boilerplate at all here.

On Aug 26, 2016, at 7:30 PM, Jens Persson <jens@bitcycle.com <mailto:jens@bitcycle.com>> wrote:

I understand.
It's just very tempting to try and use the new static computed properties for eg 23 and 52 etc.
I guess I'll just have to write a lot of boilerplate, or perhaps a protocol that is just implemented by Double and Float (that will be very similar to BinaryFloatingPoint in a lot of ways).
/Jens

On Sat, Aug 27, 2016 at 1:25 AM, Stephen Canon <scanon@apple.com> wrote:
This doesn’t really scale up very well, though. BinaryFloatingPoint needs to also be able to model e.g. Float2048 or similar; we generally don't want to require that RawExponent to be the same type as RawSignificand (which I think is what you’re really suggesting), because in typical bignum usage significands are much larger than exponents.

It sounds like maybe you actually want to be operating directly on bitPatterns, rather than the abstract fields of the types.

– Steve

On Aug 26, 2016, at 7:21 PM, Jens Persson <jens@bitcycle.com> wrote:

Oh, to more directly answer your question: I don't like having to create a UInt (UInt64) value when all my bit manipulaton code happens in UInt32 (for Float) for example.

The most probable context for using these computed properties and types of BinaryFloatingPoint is one in which specific fixed width types really matters a lot (look at the name of the protocol and the properties and assocated types we are talking about).

/Jens

On Sat, Aug 27, 2016 at 1:15 AM, Jens Persson <jens@bitcycle.com> wrote:
Reason for asking is that I have this:

extension Double {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        let bitPattern = s | (1023 << 52)
        self = unsafeBitCast(bitPattern, to: Double.self) - 1.0
    }
}
extension Float {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        let bitPattern = s | (127 << 23)
        self = unsafeBitCast(bitPattern, to: Float.self) - 1.0
    }
}

But they would be better as:
extension BinaryFloatingPoint {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        ... problems here, have to try casting things into RawSignificand's type ...
    }
}

Please have a go at that and perhaps you see what I mean or you will come up with a nice solution that I have missed. (Speed is very important btw.)

/Jens

On Sat, Aug 27, 2016 at 1:02 AM, Stephen Canon <scanon@apple.com> wrote:
> On Aug 26, 2016, at 6:06 PM, Jens Persson via swift-dev <swift-dev@swift.org> wrote:
>
> I can understand why
> Double.RawSignificand is UInt64
> and
> Float.RawSignificand is UInt32
>
> But I can't understand why both
> Double.RawExponent
> and
> Float.RawExponent
> should be UInt.
>
> Why aren't they also just UInt64 and UInt32, resp.?

Let me flip the question: why would they be UInt64 and UInt32? Absent a reason to prefer a specific fixed-with type, Swift integers should generally default to being [U]Int (and ideally Int, but RawExponent is Unsigned).

– Steve

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

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


(Jens Persson) #10

Correction " ... a protocol that only Double and Float conforms to ...".

···

On Sat, Aug 27, 2016 at 1:30 AM, Jens Persson <jens@bitcycle.com> wrote:

I understand.
It's just very tempting to try and use the new static computed properties
for eg 23 and 52 etc.
I guess I'll just have to write a lot of boilerplate, or perhaps a
protocol that is just implemented by Double and Float (that will be very
similar to BinaryFloatingPoint in a lot of ways).
/Jens

On Sat, Aug 27, 2016 at 1:25 AM, Stephen Canon <scanon@apple.com> wrote:

This doesn’t really scale up very well, though. BinaryFloatingPoint
needs to also be able to model e.g. Float2048 or similar; we generally
don't want to require that RawExponent to be the same type as
RawSignificand (which I think is what you’re really suggesting), because in
typical bignum usage significands are much larger than exponents.

It sounds like maybe you actually want to be operating directly on
bitPatterns, rather than the abstract fields of the types.

– Steve

On Aug 26, 2016, at 7:21 PM, Jens Persson <jens@bitcycle.com> wrote:

Oh, to more directly answer your question: I don't like having to create
a UInt (UInt64) value when all my bit manipulaton code happens in UInt32
(for Float) for example.

The most probable context for using these computed properties and types
of BinaryFloatingPoint is one in which specific fixed width types really
matters a lot (look at the name of the protocol and the properties and
assocated types we are talking about).

/Jens

On Sat, Aug 27, 2016 at 1:15 AM, Jens Persson <jens@bitcycle.com> wrote:

Reason for asking is that I have this:

extension Double {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        let bitPattern = s | (1023 << 52)
        self = unsafeBitCast(bitPattern, to: Double.self) - 1.0
    }
}
extension Float {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        let bitPattern = s | (127 << 23)
        self = unsafeBitCast(bitPattern, to: Float.self) - 1.0
    }
}

But they would be better as:
extension BinaryFloatingPoint {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        ... problems here, have to try casting things into
RawSignificand's type ...
    }
}

Please have a go at that and perhaps you see what I mean or you will
come up with a nice solution that I have missed. (Speed is very important
btw.)

/Jens

On Sat, Aug 27, 2016 at 1:02 AM, Stephen Canon <scanon@apple.com> wrote:

> On Aug 26, 2016, at 6:06 PM, Jens Persson via swift-dev < >>>> swift-dev@swift.org> wrote:
>
> I can understand why
> Double.RawSignificand is UInt64
> and
> Float.RawSignificand is UInt32
>
> But I can't understand why both
> Double.RawExponent
> and
> Float.RawExponent
> should be UInt.
>
> Why aren't they also just UInt64 and UInt32, resp.?

Let me flip the question: why would they be UInt64 and UInt32? Absent
a reason to prefer a specific fixed-with type, Swift integers should
generally default to being [U]Int (and ideally Int, but RawExponent is
Unsigned).

– Steve


(Jens Persson) #11

The above is just a useful init for Double and Float. For example I use it
for creating random Double's and Float's in the unit range [0, 1) from 64
bit prng like xorshift128Plus or xoroshiro128Plus.

It would also be used when trying to write something like this:

Double.init(unitRangeMapped value: Int8)
Double.init(unitRangeMapped value: UInt8)
Double.init(unitRangeMapped value: Int16)
Double.init(unitRangeMapped value: UInt16)
...
Float.init(unitRangeMapped value: Int8)
Float.init(unitRangeMapped value: UInt8)
Float.init(unitRangeMapped value: Int16)
Float.init(unitRangeMapped value: UInt16)
...

Or perhaps that could be better written the other way around, as instance
methods for all IntegerTypes, result in Float and Double:

let f: Float = UInt8(123).mappedToUnitRange
let d: Double = Int8(-123).mappedToUnitRange

in any case, it would be nice if I could write these as one method (or
computed property) in a protocol extension.

/Jens

···

On Sat, Aug 27, 2016 at 1:38 AM, Stephen Canon <scanon@apple.com> wrote:

Where does your RawSignificand input come from? Is that really the type
that you want?

I don’t think you really need very much boilerplate at all here.

On Aug 26, 2016, at 7:30 PM, Jens Persson <jens@bitcycle.com> wrote:

I understand.
It's just very tempting to try and use the new static computed properties
for eg 23 and 52 etc.
I guess I'll just have to write a lot of boilerplate, or perhaps a
protocol that is just implemented by Double and Float (that will be very
similar to BinaryFloatingPoint in a lot of ways).
/Jens

On Sat, Aug 27, 2016 at 1:25 AM, Stephen Canon <scanon@apple.com> wrote:

This doesn’t really scale up very well, though. BinaryFloatingPoint
needs to also be able to model e.g. Float2048 or similar; we generally
don't want to require that RawExponent to be the same type as
RawSignificand (which I think is what you’re really suggesting), because in
typical bignum usage significands are much larger than exponents.

It sounds like maybe you actually want to be operating directly on
bitPatterns, rather than the abstract fields of the types.

– Steve

On Aug 26, 2016, at 7:21 PM, Jens Persson <jens@bitcycle.com> wrote:

Oh, to more directly answer your question: I don't like having to create
a UInt (UInt64) value when all my bit manipulaton code happens in UInt32
(for Float) for example.

The most probable context for using these computed properties and types
of BinaryFloatingPoint is one in which specific fixed width types really
matters a lot (look at the name of the protocol and the properties and
assocated types we are talking about).

/Jens

On Sat, Aug 27, 2016 at 1:15 AM, Jens Persson <jens@bitcycle.com> wrote:

Reason for asking is that I have this:

extension Double {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        let bitPattern = s | (1023 << 52)
        self = unsafeBitCast(bitPattern, to: Double.self) - 1.0
    }
}
extension Float {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        let bitPattern = s | (127 << 23)
        self = unsafeBitCast(bitPattern, to: Float.self) - 1.0
    }
}

But they would be better as:
extension BinaryFloatingPoint {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        ... problems here, have to try casting things into
RawSignificand's type ...
    }
}

Please have a go at that and perhaps you see what I mean or you will
come up with a nice solution that I have missed. (Speed is very important
btw.)

/Jens

On Sat, Aug 27, 2016 at 1:02 AM, Stephen Canon <scanon@apple.com> wrote:

> On Aug 26, 2016, at 6:06 PM, Jens Persson via swift-dev < >>>> swift-dev@swift.org> wrote:
>
> I can understand why
> Double.RawSignificand is UInt64
> and
> Float.RawSignificand is UInt32
>
> But I can't understand why both
> Double.RawExponent
> and
> Float.RawExponent
> should be UInt.
>
> Why aren't they also just UInt64 and UInt32, resp.?

Let me flip the question: why would they be UInt64 and UInt32? Absent
a reason to prefer a specific fixed-with type, Swift integers should
generally default to being [U]Int (and ideally Int, but RawExponent is
Unsigned).

– Steve


(Jens Persson) #12

Thanks, but there seem to be something not working the same as in my
original code, here is a quick test of your code:

protocol BinaryFloatingPointWithBitPattern: BinaryFloatingPoint {
    init(bitPattern: RawSignificand)
    var bitPattern: RawSignificand { get }
}

extension Float: BinaryFloatingPointWithBitPattern { }
extension Double: BinaryFloatingPointWithBitPattern { }

extension BinaryFloatingPointWithBitPattern {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        self = Self(bitPattern: Self(1).bitPattern | s) - 1
    }
}

typealias T = Double
// typealias T = Float

let allSignificantBitsSet = T.RawSignificand((1 << T.significandBitCount) -
1)
print("bits set in signigicant:", String(allSignificantBitsSet, radix:
2).characters.count) // 52
let a = T.init(bitPattern: 0)
let b = T.init(bitPattern: allSignificantBitsSet)
print(a) // 0.0, correct.
print(b) // 2.2250738585072e-308. Wrong, this should be (1.0).nextDown.

···

On Sat, Aug 27, 2016 at 1:57 AM, Stephen Canon <scanon@apple.com> wrote:

If BinaryFloatingPoint had init(_: RawSignificand), you could also just
write:

extension BinaryFloatingPoint {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        self = Self(s) * .ulpOfOne
    }
}

(this is why I ask if RawSignificand is really the type you want; if you
use some concrete integer type this will work). But once we have all the
new integer protocol conformances, we’ll have a generic init from any
integer type (this was already reviewed for FloatingPoint, but isn’t
implementable without the Integer support), which will also make this
possible.

On Aug 26, 2016, at 7:47 PM, Stephen Canon via swift-dev < > swift-dev@swift.org> wrote:

Assuming RawSignificand really is the type you want, I think this does
what you’re looking for?

protocol BinaryFloatingPointWithBitPattern: BinaryFloatingPoint {
    init(bitPattern: RawSignificand)
    var bitPattern: RawSignificand { get }
}

extension Float: BinaryFloatingPointWithBitPattern { }
extension Double: BinaryFloatingPointWithBitPattern { }

extension BinaryFloatingPointWithBitPattern {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        self = Self(bitPattern: Self(1).bitPattern | s) - 1
    }
}

On Aug 26, 2016, at 7:38 PM, Stephen Canon via swift-dev < > swift-dev@swift.org> wrote:

Where does your RawSignificand input come from? Is that really the type
that you want?

I don’t think you really need very much boilerplate at all here.

On Aug 26, 2016, at 7:30 PM, Jens Persson <jens@bitcycle.com> wrote:

I understand.
It's just very tempting to try and use the new static computed properties
for eg 23 and 52 etc.
I guess I'll just have to write a lot of boilerplate, or perhaps a
protocol that is just implemented by Double and Float (that will be very
similar to BinaryFloatingPoint in a lot of ways).
/Jens

On Sat, Aug 27, 2016 at 1:25 AM, Stephen Canon <scanon@apple.com> wrote:
This doesn’t really scale up very well, though. BinaryFloatingPoint needs
to also be able to model e.g. Float2048 or similar; we generally don't want
to require that RawExponent to be the same type as RawSignificand (which I
think is what you’re really suggesting), because in typical bignum usage
significands are much larger than exponents.

It sounds like maybe you actually want to be operating directly on
bitPatterns, rather than the abstract fields of the types.

– Steve

On Aug 26, 2016, at 7:21 PM, Jens Persson <jens@bitcycle.com> wrote:

Oh, to more directly answer your question: I don't like having to create a
UInt (UInt64) value when all my bit manipulaton code happens in UInt32 (for
Float) for example.

The most probable context for using these computed properties and types of
BinaryFloatingPoint is one in which specific fixed width types really
matters a lot (look at the name of the protocol and the properties and
assocated types we are talking about).

/Jens

On Sat, Aug 27, 2016 at 1:15 AM, Jens Persson <jens@bitcycle.com> wrote:
Reason for asking is that I have this:

extension Double {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        let bitPattern = s | (1023 << 52)
        self = unsafeBitCast(bitPattern, to: Double.self) - 1.0
    }
}
extension Float {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        let bitPattern = s | (127 << 23)
        self = unsafeBitCast(bitPattern, to: Float.self) - 1.0
    }
}

But they would be better as:
extension BinaryFloatingPoint {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        ... problems here, have to try casting things into
RawSignificand's type ...
    }
}

Please have a go at that and perhaps you see what I mean or you will come
up with a nice solution that I have missed. (Speed is very important btw.)

/Jens

On Sat, Aug 27, 2016 at 1:02 AM, Stephen Canon <scanon@apple.com> wrote:
> On Aug 26, 2016, at 6:06 PM, Jens Persson via swift-dev < > swift-dev@swift.org> wrote:
>
> I can understand why
> Double.RawSignificand is UInt64
> and
> Float.RawSignificand is UInt32
>
> But I can't understand why both
> Double.RawExponent
> and
> Float.RawExponent
> should be UInt.
>
> Why aren't they also just UInt64 and UInt32, resp.?

Let me flip the question: why would they be UInt64 and UInt32? Absent a
reason to prefer a specific fixed-with type, Swift integers should
generally default to being [U]Int (and ideally Int, but RawExponent
is Unsigned).

– Steve

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

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


(Stephen Canon) #13

Note that with the bug fixed, the result will still not be 1.nextDown, because the size of an ulp changes at 1; the values you produce will be space .ulpOfOne apart, but 1.nextDown is 1 - ulpOfOne/2.

– Steve

···

On Aug 26, 2016, at 8:00 PM, Jens Persson <jens@bitcycle.com> wrote:

Thanks, but there seem to be something not working the same as in my original code, here is a quick test of your code:

protocol BinaryFloatingPointWithBitPattern: BinaryFloatingPoint {
    init(bitPattern: RawSignificand)
    var bitPattern: RawSignificand { get }
}

extension Float: BinaryFloatingPointWithBitPattern { }
extension Double: BinaryFloatingPointWithBitPattern { }

extension BinaryFloatingPointWithBitPattern {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        self = Self(bitPattern: Self(1).bitPattern | s) - 1
    }
}

typealias T = Double
// typealias T = Float

let allSignificantBitsSet = T.RawSignificand((1 << T.significandBitCount) - 1)
print("bits set in signigicant:", String(allSignificantBitsSet, radix: 2).characters.count) // 52
let a = T.init(bitPattern: 0)
let b = T.init(bitPattern: allSignificantBitsSet)
print(a) // 0.0, correct.
print(b) // 2.2250738585072e-308. Wrong, this should be (1.0).nextDown.

On Sat, Aug 27, 2016 at 1:57 AM, Stephen Canon <scanon@apple.com <mailto:scanon@apple.com>> wrote:
If BinaryFloatingPoint had init(_: RawSignificand), you could also just write:

extension BinaryFloatingPoint {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        self = Self(s) * .ulpOfOne
    }
}

(this is why I ask if RawSignificand is really the type you want; if you use some concrete integer type this will work). But once we have all the new integer protocol conformances, we’ll have a generic init from any integer type (this was already reviewed for FloatingPoint, but isn’t implementable without the Integer support), which will also make this possible.

On Aug 26, 2016, at 7:47 PM, Stephen Canon via swift-dev <swift-dev@swift.org <mailto:swift-dev@swift.org>> wrote:

Assuming RawSignificand really is the type you want, I think this does what you’re looking for?

protocol BinaryFloatingPointWithBitPattern: BinaryFloatingPoint {
    init(bitPattern: RawSignificand)
    var bitPattern: RawSignificand { get }
}

extension Float: BinaryFloatingPointWithBitPattern { }
extension Double: BinaryFloatingPointWithBitPattern { }

extension BinaryFloatingPointWithBitPattern {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        self = Self(bitPattern: Self(1).bitPattern | s) - 1
    }
}

On Aug 26, 2016, at 7:38 PM, Stephen Canon via swift-dev <swift-dev@swift.org <mailto:swift-dev@swift.org>> wrote:

Where does your RawSignificand input come from? Is that really the type that you want?

I don’t think you really need very much boilerplate at all here.

On Aug 26, 2016, at 7:30 PM, Jens Persson <jens@bitcycle.com <mailto:jens@bitcycle.com>> wrote:

I understand.
It's just very tempting to try and use the new static computed properties for eg 23 and 52 etc.
I guess I'll just have to write a lot of boilerplate, or perhaps a protocol that is just implemented by Double and Float (that will be very similar to BinaryFloatingPoint in a lot of ways).
/Jens

On Sat, Aug 27, 2016 at 1:25 AM, Stephen Canon <scanon@apple.com <mailto:scanon@apple.com>> wrote:
This doesn’t really scale up very well, though. BinaryFloatingPoint needs to also be able to model e.g. Float2048 or similar; we generally don't want to require that RawExponent to be the same type as RawSignificand (which I think is what you’re really suggesting), because in typical bignum usage significands are much larger than exponents.

It sounds like maybe you actually want to be operating directly on bitPatterns, rather than the abstract fields of the types.

– Steve

On Aug 26, 2016, at 7:21 PM, Jens Persson <jens@bitcycle.com <mailto:jens@bitcycle.com>> wrote:

Oh, to more directly answer your question: I don't like having to create a UInt (UInt64) value when all my bit manipulaton code happens in UInt32 (for Float) for example.

The most probable context for using these computed properties and types of BinaryFloatingPoint is one in which specific fixed width types really matters a lot (look at the name of the protocol and the properties and assocated types we are talking about).

/Jens

On Sat, Aug 27, 2016 at 1:15 AM, Jens Persson <jens@bitcycle.com <mailto:jens@bitcycle.com>> wrote:
Reason for asking is that I have this:

extension Double {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        let bitPattern = s | (1023 << 52)
        self = unsafeBitCast(bitPattern, to: Double.self) - 1.0
    }
}
extension Float {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        let bitPattern = s | (127 << 23)
        self = unsafeBitCast(bitPattern, to: Float.self) - 1.0
    }
}

But they would be better as:
extension BinaryFloatingPoint {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        ... problems here, have to try casting things into RawSignificand's type ...
    }
}

Please have a go at that and perhaps you see what I mean or you will come up with a nice solution that I have missed. (Speed is very important btw.)

/Jens

On Sat, Aug 27, 2016 at 1:02 AM, Stephen Canon <scanon@apple.com <mailto:scanon@apple.com>> wrote:
> On Aug 26, 2016, at 6:06 PM, Jens Persson via swift-dev <swift-dev@swift.org <mailto:swift-dev@swift.org>> wrote:
>
> I can understand why
> Double.RawSignificand is UInt64
> and
> Float.RawSignificand is UInt32
>
> But I can't understand why both
> Double.RawExponent
> and
> Float.RawExponent
> should be UInt.
>
> Why aren't they also just UInt64 and UInt32, resp.?

Let me flip the question: why would they be UInt64 and UInt32? Absent a reason to prefer a specific fixed-with type, Swift integers should generally default to being [U]Int (and ideally Int, but RawExponent is Unsigned).

– Steve

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

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


(Jens Persson) #14

Ouch, saw my mistake : )

···

On Sat, Aug 27, 2016 at 2:00 AM, Jens Persson <jens@bitcycle.com> wrote:

Thanks, but there seem to be something not working the same as in my
original code, here is a quick test of your code:

protocol BinaryFloatingPointWithBitPattern: BinaryFloatingPoint {
    init(bitPattern: RawSignificand)
    var bitPattern: RawSignificand { get }
}

extension Float: BinaryFloatingPointWithBitPattern { }
extension Double: BinaryFloatingPointWithBitPattern { }

extension BinaryFloatingPointWithBitPattern {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        self = Self(bitPattern: Self(1).bitPattern | s) - 1
    }
}

typealias T = Double
// typealias T = Float

let allSignificantBitsSet = T.RawSignificand((1 << T.significandBitCount)
- 1)
print("bits set in signigicant:", String(allSignificantBitsSet, radix:
2).characters.count) // 52
let a = T.init(bitPattern: 0)
let b = T.init(bitPattern: allSignificantBitsSet)
print(a) // 0.0, correct.
print(b) // 2.2250738585072e-308. Wrong, this should be (1.0).nextDown.

On Sat, Aug 27, 2016 at 1:57 AM, Stephen Canon <scanon@apple.com> wrote:

If BinaryFloatingPoint had init(_: RawSignificand), you could also just
write:

extension BinaryFloatingPoint {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        self = Self(s) * .ulpOfOne
    }
}

(this is why I ask if RawSignificand is really the type you want; if you
use some concrete integer type this will work). But once we have all the
new integer protocol conformances, we’ll have a generic init from any
integer type (this was already reviewed for FloatingPoint, but isn’t
implementable without the Integer support), which will also make this
possible.

On Aug 26, 2016, at 7:47 PM, Stephen Canon via swift-dev < >> swift-dev@swift.org> wrote:

Assuming RawSignificand really is the type you want, I think this does
what you’re looking for?

protocol BinaryFloatingPointWithBitPattern: BinaryFloatingPoint {
    init(bitPattern: RawSignificand)
    var bitPattern: RawSignificand { get }
}

extension Float: BinaryFloatingPointWithBitPattern { }
extension Double: BinaryFloatingPointWithBitPattern { }

extension BinaryFloatingPointWithBitPattern {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        self = Self(bitPattern: Self(1).bitPattern | s) - 1
    }
}

On Aug 26, 2016, at 7:38 PM, Stephen Canon via swift-dev < >> swift-dev@swift.org> wrote:

Where does your RawSignificand input come from? Is that really the type
that you want?

I don’t think you really need very much boilerplate at all here.

On Aug 26, 2016, at 7:30 PM, Jens Persson <jens@bitcycle.com> wrote:

I understand.
It's just very tempting to try and use the new static computed properties
for eg 23 and 52 etc.
I guess I'll just have to write a lot of boilerplate, or perhaps a
protocol that is just implemented by Double and Float (that will be very
similar to BinaryFloatingPoint in a lot of ways).
/Jens

On Sat, Aug 27, 2016 at 1:25 AM, Stephen Canon <scanon@apple.com> wrote:
This doesn’t really scale up very well, though. BinaryFloatingPoint
needs to also be able to model e.g. Float2048 or similar; we generally
don't want to require that RawExponent to be the same type as
RawSignificand (which I think is what you’re really suggesting), because in
typical bignum usage significands are much larger than exponents.

It sounds like maybe you actually want to be operating directly on
bitPatterns, rather than the abstract fields of the types.

– Steve

On Aug 26, 2016, at 7:21 PM, Jens Persson <jens@bitcycle.com> wrote:

Oh, to more directly answer your question: I don't like having to create
a UInt (UInt64) value when all my bit manipulaton code happens in UInt32
(for Float) for example.

The most probable context for using these computed properties and types
of BinaryFloatingPoint is one in which specific fixed width types really
matters a lot (look at the name of the protocol and the properties and
assocated types we are talking about).

/Jens

On Sat, Aug 27, 2016 at 1:15 AM, Jens Persson <jens@bitcycle.com> wrote:
Reason for asking is that I have this:

extension Double {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        let bitPattern = s | (1023 << 52)
        self = unsafeBitCast(bitPattern, to: Double.self) - 1.0
    }
}
extension Float {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        let bitPattern = s | (127 << 23)
        self = unsafeBitCast(bitPattern, to: Float.self) - 1.0
    }
}

But they would be better as:
extension BinaryFloatingPoint {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        ... problems here, have to try casting things into
RawSignificand's type ...
    }
}

Please have a go at that and perhaps you see what I mean or you will come
up with a nice solution that I have missed. (Speed is very important btw.)

/Jens

On Sat, Aug 27, 2016 at 1:02 AM, Stephen Canon <scanon@apple.com> wrote:
> On Aug 26, 2016, at 6:06 PM, Jens Persson via swift-dev < >> swift-dev@swift.org> wrote:
>
> I can understand why
> Double.RawSignificand is UInt64
> and
> Float.RawSignificand is UInt32
>
> But I can't understand why both
> Double.RawExponent
> and
> Float.RawExponent
> should be UInt.
>
> Why aren't they also just UInt64 and UInt32, resp.?

Let me flip the question: why would they be UInt64 and UInt32? Absent a
reason to prefer a specific fixed-with type, Swift integers should
generally default to being [U]Int (and ideally Int, but RawExponent
is Unsigned).

– Steve

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

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


(Jens Persson) #15

Ah, right! Thanks again.
How would you make all integer type (UIntN, IntN) convertible/mappable from
their respective [.min, .max] range to Double/Float unit range [0, 1)?
/Jens

···

On Sat, Aug 27, 2016 at 2:06 AM, Stephen Canon <scanon@apple.com> wrote:

Note that with the bug fixed, the result will still not be 1.nextDown,
because the size of an ulp changes at 1; the values you produce will be
space .ulpOfOne apart, but 1.nextDown is 1 - ulpOfOne/2.

– Steve

On Aug 26, 2016, at 8:00 PM, Jens Persson <jens@bitcycle.com> wrote:

Thanks, but there seem to be something not working the same as in my
original code, here is a quick test of your code:

protocol BinaryFloatingPointWithBitPattern: BinaryFloatingPoint {
    init(bitPattern: RawSignificand)
    var bitPattern: RawSignificand { get }
}

extension Float: BinaryFloatingPointWithBitPattern { }
extension Double: BinaryFloatingPointWithBitPattern { }

extension BinaryFloatingPointWithBitPattern {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        self = Self(bitPattern: Self(1).bitPattern | s) - 1
    }
}

typealias T = Double
// typealias T = Float

let allSignificantBitsSet = T.RawSignificand((1 << T.significandBitCount)
- 1)
print("bits set in signigicant:", String(allSignificantBitsSet, radix:
2).characters.count) // 52
let a = T.init(bitPattern: 0)
let b = T.init(bitPattern: allSignificantBitsSet)
print(a) // 0.0, correct.
print(b) // 2.2250738585072e-308. Wrong, this should be (1.0).nextDown.

On Sat, Aug 27, 2016 at 1:57 AM, Stephen Canon <scanon@apple.com> wrote:

If BinaryFloatingPoint had init(_: RawSignificand), you could also just
write:

extension BinaryFloatingPoint {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        self = Self(s) * .ulpOfOne
    }
}

(this is why I ask if RawSignificand is really the type you want; if you
use some concrete integer type this will work). But once we have all the
new integer protocol conformances, we’ll have a generic init from any
integer type (this was already reviewed for FloatingPoint, but isn’t
implementable without the Integer support), which will also make this
possible.

On Aug 26, 2016, at 7:47 PM, Stephen Canon via swift-dev < >> swift-dev@swift.org> wrote:

Assuming RawSignificand really is the type you want, I think this does
what you’re looking for?

protocol BinaryFloatingPointWithBitPattern: BinaryFloatingPoint {
    init(bitPattern: RawSignificand)
    var bitPattern: RawSignificand { get }
}

extension Float: BinaryFloatingPointWithBitPattern { }
extension Double: BinaryFloatingPointWithBitPattern { }

extension BinaryFloatingPointWithBitPattern {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        self = Self(bitPattern: Self(1).bitPattern | s) - 1
    }
}

On Aug 26, 2016, at 7:38 PM, Stephen Canon via swift-dev < >> swift-dev@swift.org> wrote:

Where does your RawSignificand input come from? Is that really the type
that you want?

I don’t think you really need very much boilerplate at all here.

On Aug 26, 2016, at 7:30 PM, Jens Persson <jens@bitcycle.com> wrote:

I understand.
It's just very tempting to try and use the new static computed properties
for eg 23 and 52 etc.
I guess I'll just have to write a lot of boilerplate, or perhaps a
protocol that is just implemented by Double and Float (that will be very
similar to BinaryFloatingPoint in a lot of ways).
/Jens

On Sat, Aug 27, 2016 at 1:25 AM, Stephen Canon <scanon@apple.com> wrote:
This doesn’t really scale up very well, though. BinaryFloatingPoint
needs to also be able to model e.g. Float2048 or similar; we generally
don't want to require that RawExponent to be the same type as
RawSignificand (which I think is what you’re really suggesting), because in
typical bignum usage significands are much larger than exponents.

It sounds like maybe you actually want to be operating directly on
bitPatterns, rather than the abstract fields of the types.

– Steve

On Aug 26, 2016, at 7:21 PM, Jens Persson <jens@bitcycle.com> wrote:

Oh, to more directly answer your question: I don't like having to create
a UInt (UInt64) value when all my bit manipulaton code happens in UInt32
(for Float) for example.

The most probable context for using these computed properties and types
of BinaryFloatingPoint is one in which specific fixed width types really
matters a lot (look at the name of the protocol and the properties and
assocated types we are talking about).

/Jens

On Sat, Aug 27, 2016 at 1:15 AM, Jens Persson <jens@bitcycle.com> wrote:
Reason for asking is that I have this:

extension Double {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        let bitPattern = s | (1023 << 52)
        self = unsafeBitCast(bitPattern, to: Double.self) - 1.0
    }
}
extension Float {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        let bitPattern = s | (127 << 23)
        self = unsafeBitCast(bitPattern, to: Float.self) - 1.0
    }
}

But they would be better as:
extension BinaryFloatingPoint {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        ... problems here, have to try casting things into
RawSignificand's type ...
    }
}

Please have a go at that and perhaps you see what I mean or you will come
up with a nice solution that I have missed. (Speed is very important btw.)

/Jens

On Sat, Aug 27, 2016 at 1:02 AM, Stephen Canon <scanon@apple.com> wrote:
> On Aug 26, 2016, at 6:06 PM, Jens Persson via swift-dev < >> swift-dev@swift.org> wrote:
>
> I can understand why
> Double.RawSignificand is UInt64
> and
> Float.RawSignificand is UInt32
>
> But I can't understand why both
> Double.RawExponent
> and
> Float.RawExponent
> should be UInt.
>
> Why aren't they also just UInt64 and UInt32, resp.?

Let me flip the question: why would they be UInt64 and UInt32? Absent a
reason to prefer a specific fixed-with type, Swift integers should
generally default to being [U]Int (and ideally Int, but RawExponent
is Unsigned).

– Steve

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

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


(Stephen Canon) #16

For any given concrete type, it’s pretty straightforward to map [0, .max] to [0,1) — note that this is a bit different from what you seem to have been doing originally, mapping e.g. [0, 2**52) to [0, 1):

    init(unitRange s: UInt64) {
        self = Self(s >> UInt64(63 - Self.significandBitCount)) * .ulpOfOne/2
    }

Making this generic over integer types is painful without the SE-0104 integer protocols, however.

– Steve

···

On Aug 26, 2016, at 8:13 PM, Jens Persson <jens@bitcycle.com> wrote:

Ah, right! Thanks again.
How would you make all integer type (UIntN, IntN) convertible/mappable from their respective [.min, .max] range to Double/Float unit range [0, 1)?
/Jens

On Sat, Aug 27, 2016 at 2:06 AM, Stephen Canon <scanon@apple.com <mailto:scanon@apple.com>> wrote:
Note that with the bug fixed, the result will still not be 1.nextDown, because the size of an ulp changes at 1; the values you produce will be space .ulpOfOne apart, but 1.nextDown is 1 - ulpOfOne/2.

– Steve

On Aug 26, 2016, at 8:00 PM, Jens Persson <jens@bitcycle.com <mailto:jens@bitcycle.com>> wrote:

Thanks, but there seem to be something not working the same as in my original code, here is a quick test of your code:

protocol BinaryFloatingPointWithBitPattern: BinaryFloatingPoint {
    init(bitPattern: RawSignificand)
    var bitPattern: RawSignificand { get }
}

extension Float: BinaryFloatingPointWithBitPattern { }
extension Double: BinaryFloatingPointWithBitPattern { }

extension BinaryFloatingPointWithBitPattern {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        self = Self(bitPattern: Self(1).bitPattern | s) - 1
    }
}

typealias T = Double
// typealias T = Float

let allSignificantBitsSet = T.RawSignificand((1 << T.significandBitCount) - 1)
print("bits set in signigicant:", String(allSignificantBitsSet, radix: 2).characters.count) // 52
let a = T.init(bitPattern: 0)
let b = T.init(bitPattern: allSignificantBitsSet)
print(a) // 0.0, correct.
print(b) // 2.2250738585072e-308. Wrong, this should be (1.0).nextDown.

On Sat, Aug 27, 2016 at 1:57 AM, Stephen Canon <scanon@apple.com <mailto:scanon@apple.com>> wrote:
If BinaryFloatingPoint had init(_: RawSignificand), you could also just write:

extension BinaryFloatingPoint {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        self = Self(s) * .ulpOfOne
    }
}

(this is why I ask if RawSignificand is really the type you want; if you use some concrete integer type this will work). But once we have all the new integer protocol conformances, we’ll have a generic init from any integer type (this was already reviewed for FloatingPoint, but isn’t implementable without the Integer support), which will also make this possible.

On Aug 26, 2016, at 7:47 PM, Stephen Canon via swift-dev <swift-dev@swift.org <mailto:swift-dev@swift.org>> wrote:

Assuming RawSignificand really is the type you want, I think this does what you’re looking for?

protocol BinaryFloatingPointWithBitPattern: BinaryFloatingPoint {
    init(bitPattern: RawSignificand)
    var bitPattern: RawSignificand { get }
}

extension Float: BinaryFloatingPointWithBitPattern { }
extension Double: BinaryFloatingPointWithBitPattern { }

extension BinaryFloatingPointWithBitPattern {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        self = Self(bitPattern: Self(1).bitPattern | s) - 1
    }
}

On Aug 26, 2016, at 7:38 PM, Stephen Canon via swift-dev <swift-dev@swift.org <mailto:swift-dev@swift.org>> wrote:

Where does your RawSignificand input come from? Is that really the type that you want?

I don’t think you really need very much boilerplate at all here.

On Aug 26, 2016, at 7:30 PM, Jens Persson <jens@bitcycle.com <mailto:jens@bitcycle.com>> wrote:

I understand.
It's just very tempting to try and use the new static computed properties for eg 23 and 52 etc.
I guess I'll just have to write a lot of boilerplate, or perhaps a protocol that is just implemented by Double and Float (that will be very similar to BinaryFloatingPoint in a lot of ways).
/Jens

On Sat, Aug 27, 2016 at 1:25 AM, Stephen Canon <scanon@apple.com <mailto:scanon@apple.com>> wrote:
This doesn’t really scale up very well, though. BinaryFloatingPoint needs to also be able to model e.g. Float2048 or similar; we generally don't want to require that RawExponent to be the same type as RawSignificand (which I think is what you’re really suggesting), because in typical bignum usage significands are much larger than exponents.

It sounds like maybe you actually want to be operating directly on bitPatterns, rather than the abstract fields of the types.

– Steve

On Aug 26, 2016, at 7:21 PM, Jens Persson <jens@bitcycle.com <mailto:jens@bitcycle.com>> wrote:

Oh, to more directly answer your question: I don't like having to create a UInt (UInt64) value when all my bit manipulaton code happens in UInt32 (for Float) for example.

The most probable context for using these computed properties and types of BinaryFloatingPoint is one in which specific fixed width types really matters a lot (look at the name of the protocol and the properties and assocated types we are talking about).

/Jens

On Sat, Aug 27, 2016 at 1:15 AM, Jens Persson <jens@bitcycle.com <mailto:jens@bitcycle.com>> wrote:
Reason for asking is that I have this:

extension Double {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        let bitPattern = s | (1023 << 52)
        self = unsafeBitCast(bitPattern, to: Double.self) - 1.0
    }
}
extension Float {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        let bitPattern = s | (127 << 23)
        self = unsafeBitCast(bitPattern, to: Float.self) - 1.0
    }
}

But they would be better as:
extension BinaryFloatingPoint {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        ... problems here, have to try casting things into RawSignificand's type ...
    }
}

Please have a go at that and perhaps you see what I mean or you will come up with a nice solution that I have missed. (Speed is very important btw.)

/Jens

On Sat, Aug 27, 2016 at 1:02 AM, Stephen Canon <scanon@apple.com <mailto:scanon@apple.com>> wrote:
> On Aug 26, 2016, at 6:06 PM, Jens Persson via swift-dev <swift-dev@swift.org <mailto:swift-dev@swift.org>> wrote:
>
> I can understand why
> Double.RawSignificand is UInt64
> and
> Float.RawSignificand is UInt32
>
> But I can't understand why both
> Double.RawExponent
> and
> Float.RawExponent
> should be UInt.
>
> Why aren't they also just UInt64 and UInt32, resp.?

Let me flip the question: why would they be UInt64 and UInt32? Absent a reason to prefer a specific fixed-with type, Swift integers should generally default to being [U]Int (and ideally Int, but RawExponent is Unsigned).

– Steve

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

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


(Jens Persson) #17

...
let a = T.init(unitRangeFromRawSignificand: 0)
let b = T.init(unitRangeFromRawSignificand: allSignificantBitsSet)
print(a) // 0.0, correct.
print(b) // (1.0).nextDown

Thanks a lot for all your help!

···

On Sat, Aug 27, 2016 at 2:01 AM, Jens Persson <jens@bitcycle.com> wrote:

Ouch, saw my mistake : )

On Sat, Aug 27, 2016 at 2:00 AM, Jens Persson <jens@bitcycle.com> wrote:

Thanks, but there seem to be something not working the same as in my
original code, here is a quick test of your code:

protocol BinaryFloatingPointWithBitPattern: BinaryFloatingPoint {
    init(bitPattern: RawSignificand)
    var bitPattern: RawSignificand { get }
}

extension Float: BinaryFloatingPointWithBitPattern { }
extension Double: BinaryFloatingPointWithBitPattern { }

extension BinaryFloatingPointWithBitPattern {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        self = Self(bitPattern: Self(1).bitPattern | s) - 1
    }
}

typealias T = Double
// typealias T = Float

let allSignificantBitsSet = T.RawSignificand((1 << T.significandBitCount)
- 1)
print("bits set in signigicant:", String(allSignificantBitsSet, radix:
2).characters.count) // 52
let a = T.init(bitPattern: 0)
let b = T.init(bitPattern: allSignificantBitsSet)
print(a) // 0.0, correct.
print(b) // 2.2250738585072e-308. Wrong, this should be (1.0).nextDown.

On Sat, Aug 27, 2016 at 1:57 AM, Stephen Canon <scanon@apple.com> wrote:

If BinaryFloatingPoint had init(_: RawSignificand), you could also just
write:

extension BinaryFloatingPoint {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        self = Self(s) * .ulpOfOne
    }
}

(this is why I ask if RawSignificand is really the type you want; if you
use some concrete integer type this will work). But once we have all the
new integer protocol conformances, we’ll have a generic init from any
integer type (this was already reviewed for FloatingPoint, but isn’t
implementable without the Integer support), which will also make this
possible.

On Aug 26, 2016, at 7:47 PM, Stephen Canon via swift-dev < >>> swift-dev@swift.org> wrote:

Assuming RawSignificand really is the type you want, I think this does
what you’re looking for?

protocol BinaryFloatingPointWithBitPattern: BinaryFloatingPoint {
    init(bitPattern: RawSignificand)
    var bitPattern: RawSignificand { get }
}

extension Float: BinaryFloatingPointWithBitPattern { }
extension Double: BinaryFloatingPointWithBitPattern { }

extension BinaryFloatingPointWithBitPattern {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        self = Self(bitPattern: Self(1).bitPattern | s) - 1
    }
}

On Aug 26, 2016, at 7:38 PM, Stephen Canon via swift-dev < >>> swift-dev@swift.org> wrote:

Where does your RawSignificand input come from? Is that really the type
that you want?

I don’t think you really need very much boilerplate at all here.

On Aug 26, 2016, at 7:30 PM, Jens Persson <jens@bitcycle.com> wrote:

I understand.
It's just very tempting to try and use the new static computed
properties for eg 23 and 52 etc.
I guess I'll just have to write a lot of boilerplate, or perhaps a
protocol that is just implemented by Double and Float (that will be very
similar to BinaryFloatingPoint in a lot of ways).
/Jens

On Sat, Aug 27, 2016 at 1:25 AM, Stephen Canon <scanon@apple.com> wrote:
This doesn’t really scale up very well, though. BinaryFloatingPoint
needs to also be able to model e.g. Float2048 or similar; we generally
don't want to require that RawExponent to be the same type as
RawSignificand (which I think is what you’re really suggesting), because in
typical bignum usage significands are much larger than exponents.

It sounds like maybe you actually want to be operating directly on
bitPatterns, rather than the abstract fields of the types.

– Steve

On Aug 26, 2016, at 7:21 PM, Jens Persson <jens@bitcycle.com> wrote:

Oh, to more directly answer your question: I don't like having to create
a UInt (UInt64) value when all my bit manipulaton code happens in UInt32
(for Float) for example.

The most probable context for using these computed properties and types
of BinaryFloatingPoint is one in which specific fixed width types really
matters a lot (look at the name of the protocol and the properties and
assocated types we are talking about).

/Jens

On Sat, Aug 27, 2016 at 1:15 AM, Jens Persson <jens@bitcycle.com> wrote:
Reason for asking is that I have this:

extension Double {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        let bitPattern = s | (1023 << 52)
        self = unsafeBitCast(bitPattern, to: Double.self) - 1.0
    }
}
extension Float {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        let bitPattern = s | (127 << 23)
        self = unsafeBitCast(bitPattern, to: Float.self) - 1.0
    }
}

But they would be better as:
extension BinaryFloatingPoint {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        ... problems here, have to try casting things into
RawSignificand's type ...
    }
}

Please have a go at that and perhaps you see what I mean or you will
come up with a nice solution that I have missed. (Speed is very important
btw.)

/Jens

On Sat, Aug 27, 2016 at 1:02 AM, Stephen Canon <scanon@apple.com> wrote:
> On Aug 26, 2016, at 6:06 PM, Jens Persson via swift-dev < >>> swift-dev@swift.org> wrote:
>
> I can understand why
> Double.RawSignificand is UInt64
> and
> Float.RawSignificand is UInt32
>
> But I can't understand why both
> Double.RawExponent
> and
> Float.RawExponent
> should be UInt.
>
> Why aren't they also just UInt64 and UInt32, resp.?

Let me flip the question: why would they be UInt64 and UInt32? Absent a
reason to prefer a specific fixed-with type, Swift integers should
generally default to being [U]Int (and ideally Int, but RawExponent
is Unsigned).

– Steve

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

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


(Jens Persson) #18

Ok, I've learned a lot, thanks!
/Jens

···

On Sat, Aug 27, 2016 at 2:26 AM, Stephen Canon <scanon@apple.com> wrote:

For any given concrete type, it’s pretty straightforward to map [0, .max]
to [0,1) — note that this is a bit different from what you seem to have
been doing originally, mapping e.g. [0, 2**52) to [0, 1):

    init(unitRange s: UInt64) {
        self = Self(s >> UInt64(63 - Self.significandBitCount)) * .
ulpOfOne/2
    }

Making this generic over integer types is painful without the SE-0104
integer protocols, however.

– Steve

On Aug 26, 2016, at 8:13 PM, Jens Persson <jens@bitcycle.com> wrote:

Ah, right! Thanks again.
How would you make all integer type (UIntN, IntN) convertible/mappable
from their respective [.min, .max] range to Double/Float unit range [0, 1)?
/Jens

On Sat, Aug 27, 2016 at 2:06 AM, Stephen Canon <scanon@apple.com> wrote:

Note that with the bug fixed, the result will still not be 1.nextDown,
because the size of an ulp changes at 1; the values you produce will be
space .ulpOfOne apart, but 1.nextDown is 1 - ulpOfOne/2.

– Steve

On Aug 26, 2016, at 8:00 PM, Jens Persson <jens@bitcycle.com> wrote:

Thanks, but there seem to be something not working the same as in my
original code, here is a quick test of your code:

protocol BinaryFloatingPointWithBitPattern: BinaryFloatingPoint {
    init(bitPattern: RawSignificand)
    var bitPattern: RawSignificand { get }
}

extension Float: BinaryFloatingPointWithBitPattern { }
extension Double: BinaryFloatingPointWithBitPattern { }

extension BinaryFloatingPointWithBitPattern {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        self = Self(bitPattern: Self(1).bitPattern | s) - 1
    }
}

typealias T = Double
// typealias T = Float

let allSignificantBitsSet = T.RawSignificand((1 << T.significandBitCount)
- 1)
print("bits set in signigicant:", String(allSignificantBitsSet, radix:
2).characters.count) // 52
let a = T.init(bitPattern: 0)
let b = T.init(bitPattern: allSignificantBitsSet)
print(a) // 0.0, correct.
print(b) // 2.2250738585072e-308. Wrong, this should be (1.0).nextDown.

On Sat, Aug 27, 2016 at 1:57 AM, Stephen Canon <scanon@apple.com> wrote:

If BinaryFloatingPoint had init(_: RawSignificand), you could also just
write:

extension BinaryFloatingPoint {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        self = Self(s) * .ulpOfOne
    }
}

(this is why I ask if RawSignificand is really the type you want; if you
use some concrete integer type this will work). But once we have all the
new integer protocol conformances, we’ll have a generic init from any
integer type (this was already reviewed for FloatingPoint, but isn’t
implementable without the Integer support), which will also make this
possible.

On Aug 26, 2016, at 7:47 PM, Stephen Canon via swift-dev < >>> swift-dev@swift.org> wrote:

Assuming RawSignificand really is the type you want, I think this does
what you’re looking for?

protocol BinaryFloatingPointWithBitPattern: BinaryFloatingPoint {
    init(bitPattern: RawSignificand)
    var bitPattern: RawSignificand { get }
}

extension Float: BinaryFloatingPointWithBitPattern { }
extension Double: BinaryFloatingPointWithBitPattern { }

extension BinaryFloatingPointWithBitPattern {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        self = Self(bitPattern: Self(1).bitPattern | s) - 1
    }
}

On Aug 26, 2016, at 7:38 PM, Stephen Canon via swift-dev < >>> swift-dev@swift.org> wrote:

Where does your RawSignificand input come from? Is that really the type
that you want?

I don’t think you really need very much boilerplate at all here.

On Aug 26, 2016, at 7:30 PM, Jens Persson <jens@bitcycle.com> wrote:

I understand.
It's just very tempting to try and use the new static computed
properties for eg 23 and 52 etc.
I guess I'll just have to write a lot of boilerplate, or perhaps a
protocol that is just implemented by Double and Float (that will be very
similar to BinaryFloatingPoint in a lot of ways).
/Jens

On Sat, Aug 27, 2016 at 1:25 AM, Stephen Canon <scanon@apple.com> wrote:
This doesn’t really scale up very well, though. BinaryFloatingPoint
needs to also be able to model e.g. Float2048 or similar; we generally
don't want to require that RawExponent to be the same type as
RawSignificand (which I think is what you’re really suggesting), because in
typical bignum usage significands are much larger than exponents.

It sounds like maybe you actually want to be operating directly on
bitPatterns, rather than the abstract fields of the types.

– Steve

On Aug 26, 2016, at 7:21 PM, Jens Persson <jens@bitcycle.com> wrote:

Oh, to more directly answer your question: I don't like having to create
a UInt (UInt64) value when all my bit manipulaton code happens in UInt32
(for Float) for example.

The most probable context for using these computed properties and types
of BinaryFloatingPoint is one in which specific fixed width types really
matters a lot (look at the name of the protocol and the properties and
assocated types we are talking about).

/Jens

On Sat, Aug 27, 2016 at 1:15 AM, Jens Persson <jens@bitcycle.com> wrote:
Reason for asking is that I have this:

extension Double {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        let bitPattern = s | (1023 << 52)
        self = unsafeBitCast(bitPattern, to: Double.self) - 1.0
    }
}
extension Float {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        let bitPattern = s | (127 << 23)
        self = unsafeBitCast(bitPattern, to: Float.self) - 1.0
    }
}

But they would be better as:
extension BinaryFloatingPoint {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        ... problems here, have to try casting things into
RawSignificand's type ...
    }
}

Please have a go at that and perhaps you see what I mean or you will
come up with a nice solution that I have missed. (Speed is very important
btw.)

/Jens

On Sat, Aug 27, 2016 at 1:02 AM, Stephen Canon <scanon@apple.com> wrote:
> On Aug 26, 2016, at 6:06 PM, Jens Persson via swift-dev < >>> swift-dev@swift.org> wrote:
>
> I can understand why
> Double.RawSignificand is UInt64
> and
> Float.RawSignificand is UInt32
>
> But I can't understand why both
> Double.RawExponent
> and
> Float.RawExponent
> should be UInt.
>
> Why aren't they also just UInt64 and UInt32, resp.?

Let me flip the question: why would they be UInt64 and UInt32? Absent a
reason to prefer a specific fixed-with type, Swift integers should
generally default to being [U]Int (and ideally Int, but RawExponent
is Unsigned).

– Steve

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

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


(Jens Persson) #19

Btw, I had a look quick at the development snapshot 08-25-a toolchain and
it seems like it has SE-0104 partly implemented.

(For example Double doesn't conform to SignedArithmetic while it does
conform to Arithmetic. And the Integer types doesn't conform to Arithmetic)

Is SE-0104 not part of Swift 3, and will thus not be included in Xcode 8 GM?

/Jens

···

On Sat, Aug 27, 2016 at 2:31 AM, Jens Persson <jens@bitcycle.com> wrote:

Ok, I've learned a lot, thanks!
/Jens

On Sat, Aug 27, 2016 at 2:26 AM, Stephen Canon <scanon@apple.com> wrote:

For any given concrete type, it’s pretty straightforward to map [0, .max]
to [0,1) — note that this is a bit different from what you seem to have
been doing originally, mapping e.g. [0, 2**52) to [0, 1):

    init(unitRange s: UInt64) {
        self = Self(s >> UInt64(63 - Self.significandBitCount)) * .
ulpOfOne/2
    }

Making this generic over integer types is painful without the SE-0104
integer protocols, however.

– Steve

On Aug 26, 2016, at 8:13 PM, Jens Persson <jens@bitcycle.com> wrote:

Ah, right! Thanks again.
How would you make all integer type (UIntN, IntN) convertible/mappable
from their respective [.min, .max] range to Double/Float unit range [0, 1)?
/Jens

On Sat, Aug 27, 2016 at 2:06 AM, Stephen Canon <scanon@apple.com> wrote:

Note that with the bug fixed, the result will still not be 1.nextDown,
because the size of an ulp changes at 1; the values you produce will be
space .ulpOfOne apart, but 1.nextDown is 1 - ulpOfOne/2.

– Steve

On Aug 26, 2016, at 8:00 PM, Jens Persson <jens@bitcycle.com> wrote:

Thanks, but there seem to be something not working the same as in my
original code, here is a quick test of your code:

protocol BinaryFloatingPointWithBitPattern: BinaryFloatingPoint {
    init(bitPattern: RawSignificand)
    var bitPattern: RawSignificand { get }
}

extension Float: BinaryFloatingPointWithBitPattern { }
extension Double: BinaryFloatingPointWithBitPattern { }

extension BinaryFloatingPointWithBitPattern {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        self = Self(bitPattern: Self(1).bitPattern | s) - 1
    }
}

typealias T = Double
// typealias T = Float

let allSignificantBitsSet = T.RawSignificand((1 <<
T.significandBitCount) - 1)
print("bits set in signigicant:", String(allSignificantBitsSet, radix:
2).characters.count) // 52
let a = T.init(bitPattern: 0)
let b = T.init(bitPattern: allSignificantBitsSet)
print(a) // 0.0, correct.
print(b) // 2.2250738585072e-308. Wrong, this should be (1.0).nextDown.

On Sat, Aug 27, 2016 at 1:57 AM, Stephen Canon <scanon@apple.com> wrote:

If BinaryFloatingPoint had init(_: RawSignificand), you could also just
write:

extension BinaryFloatingPoint {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        self = Self(s) * .ulpOfOne
    }
}

(this is why I ask if RawSignificand is really the type you want; if
you use some concrete integer type this will work). But once we have all
the new integer protocol conformances, we’ll have a generic init from any
integer type (this was already reviewed for FloatingPoint, but isn’t
implementable without the Integer support), which will also make this
possible.

On Aug 26, 2016, at 7:47 PM, Stephen Canon via swift-dev < >>>> swift-dev@swift.org> wrote:

Assuming RawSignificand really is the type you want, I think this does
what you’re looking for?

protocol BinaryFloatingPointWithBitPattern: BinaryFloatingPoint {
    init(bitPattern: RawSignificand)
    var bitPattern: RawSignificand { get }
}

extension Float: BinaryFloatingPointWithBitPattern { }
extension Double: BinaryFloatingPointWithBitPattern { }

extension BinaryFloatingPointWithBitPattern {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        self = Self(bitPattern: Self(1).bitPattern | s) - 1
    }
}

On Aug 26, 2016, at 7:38 PM, Stephen Canon via swift-dev < >>>> swift-dev@swift.org> wrote:

Where does your RawSignificand input come from? Is that really the
type that you want?

I don’t think you really need very much boilerplate at all here.

On Aug 26, 2016, at 7:30 PM, Jens Persson <jens@bitcycle.com> wrote:

I understand.
It's just very tempting to try and use the new static computed
properties for eg 23 and 52 etc.
I guess I'll just have to write a lot of boilerplate, or perhaps a
protocol that is just implemented by Double and Float (that will be very
similar to BinaryFloatingPoint in a lot of ways).
/Jens

On Sat, Aug 27, 2016 at 1:25 AM, Stephen Canon <scanon@apple.com> wrote
:
This doesn’t really scale up very well, though. BinaryFloatingPoint
needs to also be able to model e.g. Float2048 or similar; we generally
don't want to require that RawExponent to be the same type as
RawSignificand (which I think is what you’re really suggesting), because in
typical bignum usage significands are much larger than exponents.

It sounds like maybe you actually want to be operating directly on
bitPatterns, rather than the abstract fields of the types.

– Steve

On Aug 26, 2016, at 7:21 PM, Jens Persson <jens@bitcycle.com> wrote:

Oh, to more directly answer your question: I don't like having to
create a UInt (UInt64) value when all my bit manipulaton code happens in
UInt32 (for Float) for example.

The most probable context for using these computed properties and types
of BinaryFloatingPoint is one in which specific fixed width types really
matters a lot (look at the name of the protocol and the properties and
assocated types we are talking about).

/Jens

On Sat, Aug 27, 2016 at 1:15 AM, Jens Persson <jens@bitcycle.com> wr
ote:
Reason for asking is that I have this:

extension Double {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        let bitPattern = s | (1023 << 52)
        self = unsafeBitCast(bitPattern, to: Double.self) - 1.0
    }
}
extension Float {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        let bitPattern = s | (127 << 23)
        self = unsafeBitCast(bitPattern, to: Float.self) - 1.0
    }
}

But they would be better as:
extension BinaryFloatingPoint {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        ... problems here, have to try casting things into
RawSignificand's type ...
    }
}

Please have a go at that and perhaps you see what I mean or you will
come up with a nice solution that I have missed. (Speed is very important
btw.)

/Jens

On Sat, Aug 27, 2016 at 1:02 AM, Stephen Canon <scanon@apple.com> wrote
:
> On Aug 26, 2016, at 6:06 PM, Jens Persson via swift-dev < >>>> swift-dev@swift.org> wrote:
>
> I can understand why
> Double.RawSignificand is UInt64
> and
> Float.RawSignificand is UInt32
>
> But I can't understand why both
> Double.RawExponent
> and
> Float.RawExponent
> should be UInt.
>
> Why aren't they also just UInt64 and UInt32, resp.?

Let me flip the question: why would they be UInt64 and UInt32? Absent
a reason to prefer a specific fixed-with type, Swift integers should
generally default to being [U]Int (and ideally Int, but RawExponent
is Unsigned).

– Steve

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

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


(Jens Persson) #20

Oh, I just saw that SE-0104 was accepted for Swift 3:
https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160627/022977.html

Sorry for the noise, I will try to check basic things like this up before
asking here next time.

···

On Sat, Aug 27, 2016 at 10:20 AM, Jens Persson <jens@bitcycle.com> wrote:

Btw, I had a look quick at the development snapshot 08-25-a toolchain and
it seems like it has SE-0104 partly implemented.

(For example Double doesn't conform to SignedArithmetic while it does
conform to Arithmetic. And the Integer types doesn't conform to Arithmetic)

Is SE-0104 not part of Swift 3, and will thus not be included in Xcode 8
GM?

/Jens

On Sat, Aug 27, 2016 at 2:31 AM, Jens Persson <jens@bitcycle.com> wrote:

Ok, I've learned a lot, thanks!
/Jens

On Sat, Aug 27, 2016 at 2:26 AM, Stephen Canon <scanon@apple.com> wrote:

For any given concrete type, it’s pretty straightforward to map [0,
.max] to [0,1) — note that this is a bit different from what you seem to
have been doing originally, mapping e.g. [0, 2**52) to [0, 1):

    init(unitRange s: UInt64) {
        self = Self(s >> UInt64(63 - Self.significandBitCount)) * .
ulpOfOne/2
    }

Making this generic over integer types is painful without the SE-0104
integer protocols, however.

– Steve

On Aug 26, 2016, at 8:13 PM, Jens Persson <jens@bitcycle.com> wrote:

Ah, right! Thanks again.
How would you make all integer type (UIntN, IntN) convertible/mappable
from their respective [.min, .max] range to Double/Float unit range [0, 1)?
/Jens

On Sat, Aug 27, 2016 at 2:06 AM, Stephen Canon <scanon@apple.com> wrote:

Note that with the bug fixed, the result will still not be 1.nextDown,
because the size of an ulp changes at 1; the values you produce will be
space .ulpOfOne apart, but 1.nextDown is 1 - ulpOfOne/2.

– Steve

On Aug 26, 2016, at 8:00 PM, Jens Persson <jens@bitcycle.com> wrote:

Thanks, but there seem to be something not working the same as in my
original code, here is a quick test of your code:

protocol BinaryFloatingPointWithBitPattern: BinaryFloatingPoint {
    init(bitPattern: RawSignificand)
    var bitPattern: RawSignificand { get }
}

extension Float: BinaryFloatingPointWithBitPattern { }
extension Double: BinaryFloatingPointWithBitPattern { }

extension BinaryFloatingPointWithBitPattern {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        self = Self(bitPattern: Self(1).bitPattern | s) - 1
    }
}

typealias T = Double
// typealias T = Float

let allSignificantBitsSet = T.RawSignificand((1 <<
T.significandBitCount) - 1)
print("bits set in signigicant:", String(allSignificantBitsSet, radix:
2).characters.count) // 52
let a = T.init(bitPattern: 0)
let b = T.init(bitPattern: allSignificantBitsSet)
print(a) // 0.0, correct.
print(b) // 2.2250738585072e-308. Wrong, this should be (1.0).nextDown.

On Sat, Aug 27, 2016 at 1:57 AM, Stephen Canon <scanon@apple.com> >>>> wrote:

If BinaryFloatingPoint had init(_: RawSignificand), you could also
just write:

extension BinaryFloatingPoint {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        self = Self(s) * .ulpOfOne
    }
}

(this is why I ask if RawSignificand is really the type you want; if
you use some concrete integer type this will work). But once we have all
the new integer protocol conformances, we’ll have a generic init from any
integer type (this was already reviewed for FloatingPoint, but isn’t
implementable without the Integer support), which will also make this
possible.

On Aug 26, 2016, at 7:47 PM, Stephen Canon via swift-dev < >>>>> swift-dev@swift.org> wrote:

Assuming RawSignificand really is the type you want, I think this does
what you’re looking for?

protocol BinaryFloatingPointWithBitPattern: BinaryFloatingPoint {
    init(bitPattern: RawSignificand)
    var bitPattern: RawSignificand { get }
}

extension Float: BinaryFloatingPointWithBitPattern { }
extension Double: BinaryFloatingPointWithBitPattern { }

extension BinaryFloatingPointWithBitPattern {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        self = Self(bitPattern: Self(1).bitPattern | s) - 1
    }
}

On Aug 26, 2016, at 7:38 PM, Stephen Canon via swift-dev < >>>>> swift-dev@swift.org> wrote:

Where does your RawSignificand input come from? Is that really the
type that you want?

I don’t think you really need very much boilerplate at all here.

On Aug 26, 2016, at 7:30 PM, Jens Persson <jens@bitcycle.com> wrote:

I understand.
It's just very tempting to try and use the new static computed
properties for eg 23 and 52 etc.
I guess I'll just have to write a lot of boilerplate, or perhaps a
protocol that is just implemented by Double and Float (that will be very
similar to BinaryFloatingPoint in a lot of ways).
/Jens

On Sat, Aug 27, 2016 at 1:25 AM, Stephen Canon <scanon@apple.com >>>>> > wrote:
This doesn’t really scale up very well, though. BinaryFloatingPoint
needs to also be able to model e.g. Float2048 or similar; we generally
don't want to require that RawExponent to be the same type as
RawSignificand (which I think is what you’re really suggesting), because in
typical bignum usage significands are much larger than exponents.

It sounds like maybe you actually want to be operating directly on
bitPatterns, rather than the abstract fields of the types.

– Steve

On Aug 26, 2016, at 7:21 PM, Jens Persson <jens@bitcycle.com> wrote:

Oh, to more directly answer your question: I don't like having to
create a UInt (UInt64) value when all my bit manipulaton code happens in
UInt32 (for Float) for example.

The most probable context for using these computed properties and
types of BinaryFloatingPoint is one in which specific fixed width types
really matters a lot (look at the name of the protocol and the properties
and assocated types we are talking about).

/Jens

On Sat, Aug 27, 2016 at 1:15 AM, Jens Persson <jens@bitcycle.com> wr
ote:
Reason for asking is that I have this:

extension Double {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        let bitPattern = s | (1023 << 52)
        self = unsafeBitCast(bitPattern, to: Double.self) - 1.0
    }
}
extension Float {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        let bitPattern = s | (127 << 23)
        self = unsafeBitCast(bitPattern, to: Float.self) - 1.0
    }
}

But they would be better as:
extension BinaryFloatingPoint {
    init(unitRangeFromRawSignificand s: RawSignificand) {
        ... problems here, have to try casting things into
RawSignificand's type ...
    }
}

Please have a go at that and perhaps you see what I mean or you will
come up with a nice solution that I have missed. (Speed is very important
btw.)

/Jens

On Sat, Aug 27, 2016 at 1:02 AM, Stephen Canon <scanon@apple.com >>>>> > wrote:
> On Aug 26, 2016, at 6:06 PM, Jens Persson via swift-dev < >>>>> swift-dev@swift.org> wrote:
>
> I can understand why
> Double.RawSignificand is UInt64
> and
> Float.RawSignificand is UInt32
>
> But I can't understand why both
> Double.RawExponent
> and
> Float.RawExponent
> should be UInt.
>
> Why aren't they also just UInt64 and UInt32, resp.?

Let me flip the question: why would they be UInt64 and UInt32? Absent
a reason to prefer a specific fixed-with type, Swift integers should
generally default to being [U]Int (and ideally Int, but RawExponent
is Unsigned).

– Steve

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

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