Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[RFC 58] Add partial arithmetic for integer types #2865

Merged
merged 4 commits into from
Aug 29, 2018
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 68 additions & 0 deletions packages/builtin/_partial_arithmetic.pony
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@

trait _PartialArithmetic
fun add_partial[T: (Integer[T] val & Int)](x: T, y: T): T? =>
(let r: T, let overflow: Bool) = x.addc(y)
if overflow then error else r end

fun sub_partial[T: (Integer[T] val & Int)](x: T, y: T): T? =>
(let r: T, let overflow: Bool) = x.subc(y)
if overflow then error else r end

fun mul_partial[T: (Integer[T] val & Int)](x: T, y: T): T? =>
(let r: T, let overflow: Bool) = x.mulc(y)
if overflow then error else r end


primitive _UnsignedPartialArithmetic is _PartialArithmetic
fun div_partial[T: _UnsignedInteger[T] val](x: T, y: T): T? =>
if (y == T.from[U8](0)) then
error
else
x /~ y
end

fun mod_partial[T: _UnsignedInteger[T] val](x: T, y: T): T? =>
if (y == T.from[U8](0)) then
error
else
x %~ y
end

fun divmod_partial[T: _UnsignedInteger[T] val](x: T, y: T): (T, T)? =>
if (y == T.from[U8](0)) then
error
else
(x /~ y, x %~ y)
end


primitive _SignedPartialArithmetic is _PartialArithmetic

fun div_partial[T: (_SignedInteger[T, U] val & Signed), U: _UnsignedInteger[U] val](x: T, y: T): T? =>
if (y == T.from[I8](0)) or ((y == T.from[I8](I8(-1))) and (x == T.min_value())) then
error
else
x /~ y
end

fun mod_partial[T: (_SignedInteger[T, U] val & Signed), U: _UnsignedInteger[U] val](x: T, y: T): T? =>
if (y == T.from[I8](0)) or ((y == T.from[I8](I8(-1))) and (x == T.min_value())) then
error
else
x %~ y
end

fun divmod_partial[T: (_SignedInteger[T, U] val & Signed), U: _UnsignedInteger[U] val](x: T, y: T): (T, T)? =>
if (y == T.from[I8](0)) or ((y == T.from[I8](I8(-1))) and (x == T.min_value())) then
error
else
(x/~y, x %~ y)
end


Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a few style issues in this file - everywhere where you have two blank lines, it should be one blank line. See https://github.com/ponylang/ponyc/blob/master/STYLE_GUIDE.md#blank-lines

fun neg_partial[T: (_SignedInteger[T, U] val & Signed), U: _UnsignedInteger[U] val](x: T): T? =>
if x == T.min_value() then
error
else
-~x
end
46 changes: 46 additions & 0 deletions packages/builtin/real.pony
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,48 @@ trait val Integer[A: Integer[A] val] is Real[A]
"""
this %~ y

fun add_partial(y: A): A ?
"""
Add y to this number.

If the operation overflows this function errors.
"""

fun sub_partial(y: A): A ?
"""
Subtract y from this number.

If the operation overflows/underflows this function errors.
"""

fun mul_partial(y: A): A ?
"""
Multiply y with this number.

If the operation overflows this function errors.
"""

fun div_partial(y: A): A ?
"""
Divides this number by y.

If y is `0` this function errors.
"""

fun mod_partial(y: A): A ?
"""
Calculates the remainder of this number divided by y.

If y is `0` this function errors.
"""

fun divmod_partial(y: A): (A, A) ?
"""
Divides this number by y and calculates the remainder of the operation.

If y is `0` this function errors.
"""

fun neg_unsafe(): A =>
"""
Unsafe operation.
Expand Down Expand Up @@ -350,12 +392,16 @@ trait val _UnsignedInteger[A: _UnsignedInteger[A] val] is Integer[A]

fun clz_unsafe(): A
"""
Count leading zeroes.

Unsafe operation.
If this is 0, the result is undefined.
"""

fun ctz_unsafe(): A
"""
Count trailing zeroes.

Unsafe operation.
If this is 0, the result is undefined.
"""
Expand Down
126 changes: 126 additions & 0 deletions packages/builtin/signed.pony
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,24 @@ primitive I8 is _SignedInteger[I8, U8]
fun mulc(y: I8): (I8, Bool) =>
@"llvm.smul.with.overflow.i8"[(I8, Bool)](this, y)

fun add_partial(y: I8): I8 ? =>
_SignedPartialArithmetic.add_partial[I8](this, y)?

fun sub_partial(y: I8): I8 ? =>
_SignedPartialArithmetic.sub_partial[I8](this, y)?

fun mul_partial(y: I8): I8 ? =>
_SignedPartialArithmetic.mul_partial[I8](this, y)?

fun div_partial(y: I8): I8 ? =>
_SignedPartialArithmetic.div_partial[I8, U8](this, y)?

fun mod_partial(y: I8): I8 ? =>
_SignedPartialArithmetic.mod_partial[I8, U8](this, y)?

fun divmod_partial(y: I8): (I8, I8) ? =>
_SignedPartialArithmetic.divmod_partial[I8, U8](this, y)?

primitive I16 is _SignedInteger[I16, U16]
new create(value: I16) => value
new from[A: (Number & Real[A] val)](a: A) => a.i16()
Expand Down Expand Up @@ -82,6 +100,25 @@ primitive I16 is _SignedInteger[I16, U16]
fun mulc(y: I16): (I16, Bool) =>
@"llvm.smul.with.overflow.i16"[(I16, Bool)](this, y)

fun add_partial(y: I16): I16 ? =>
_SignedPartialArithmetic.add_partial[I16](this, y)?

fun sub_partial(y: I16): I16 ? =>
_SignedPartialArithmetic.sub_partial[I16](this, y)?

fun mul_partial(y: I16): I16 ? =>
_SignedPartialArithmetic.mul_partial[I16](this, y)?

fun div_partial(y: I16): I16 ? =>
_SignedPartialArithmetic.div_partial[I16, U16](this, y)?

fun mod_partial(y: I16): I16 ? =>
_SignedPartialArithmetic.mod_partial[I16, U16](this, y)?

fun divmod_partial(y: I16): (I16, I16) ? =>
_SignedPartialArithmetic.divmod_partial[I16, U16](this, y)?


primitive I32 is _SignedInteger[I32, U32]
new create(value: I32) => value
new from[A: (Number & Real[A] val)](a: A) => a.i32()
Expand Down Expand Up @@ -124,6 +161,24 @@ primitive I32 is _SignedInteger[I32, U32]
fun mulc(y: I32): (I32, Bool) =>
@"llvm.smul.with.overflow.i32"[(I32, Bool)](this, y)

fun add_partial(y: I32): I32 ? =>
_SignedPartialArithmetic.add_partial[I32](this, y)?

fun sub_partial(y: I32): I32 ? =>
_SignedPartialArithmetic.sub_partial[I32](this, y)?

fun mul_partial(y: I32): I32 ? =>
_SignedPartialArithmetic.mul_partial[I32](this, y)?

fun div_partial(y: I32): I32 ? =>
_SignedPartialArithmetic.div_partial[I32, U32](this, y)?

fun mod_partial(y: I32): I32 ? =>
_SignedPartialArithmetic.mod_partial[I32, U32](this, y)?

fun divmod_partial(y: I32): (I32, I32) ? =>
_SignedPartialArithmetic.divmod_partial[I32, U32](this, y)?

primitive I64 is _SignedInteger[I64, U64]
new create(value: I64) => value
new from[A: (Number & Real[A] val)](a: A) => a.i64()
Expand Down Expand Up @@ -167,6 +222,23 @@ primitive I64 is _SignedInteger[I64, U64]
fun mulc(y: I64): (I64, Bool) =>
_SignedCheckedArithmetic._mulc[U64, I64](this, y)

fun add_partial(y: I64): I64 ? =>
_SignedPartialArithmetic.add_partial[I64](this, y)?

fun sub_partial(y: I64): I64 ? =>
_SignedPartialArithmetic.sub_partial[I64](this, y)?

fun mul_partial(y: I64): I64 ? =>
_SignedPartialArithmetic.mul_partial[I64](this, y)?

fun div_partial(y: I64): I64 ? =>
_SignedPartialArithmetic.div_partial[I64, U64](this, y)?

fun mod_partial(y: I64): I64 ? =>
_SignedPartialArithmetic.mod_partial[I64, U64](this, y)?

fun divmod_partial(y: I64): (I64, I64) ? =>
_SignedPartialArithmetic.divmod_partial[I64, U64](this, y)?

primitive ILong is _SignedInteger[ILong, ULong]
new create(value: ILong) => value
Expand Down Expand Up @@ -263,6 +335,24 @@ primitive ILong is _SignedInteger[ILong, ULong]
_SignedCheckedArithmetic._mulc[ULong, ILong](this, y)
end

fun add_partial(y: ILong): ILong ? =>
_SignedPartialArithmetic.add_partial[ILong](this, y)?

fun sub_partial(y: ILong): ILong ? =>
_SignedPartialArithmetic.sub_partial[ILong](this, y)?

fun mul_partial(y: ILong): ILong ? =>
_SignedPartialArithmetic.mul_partial[ILong](this, y)?

fun div_partial(y: ILong): ILong ? =>
_SignedPartialArithmetic.div_partial[ILong, ULong](this, y)?

fun mod_partial(y: ILong): ILong ? =>
_SignedPartialArithmetic.mod_partial[ILong, ULong](this, y)?

fun divmod_partial(y: ILong): (ILong, ILong) ? =>
_SignedPartialArithmetic.divmod_partial[ILong, ULong](this, y)?

primitive ISize is _SignedInteger[ISize, USize]
new create(value: ISize) => value
new from[A: (Number & Real[A] val)](a: A) => a.isize()
Expand Down Expand Up @@ -357,6 +447,24 @@ primitive ISize is _SignedInteger[ISize, USize]
_SignedCheckedArithmetic._mulc[USize, ISize](this, y)
end

fun add_partial(y: ISize): ISize ? =>
_SignedPartialArithmetic.add_partial[ISize](this, y)?

fun sub_partial(y: ISize): ISize ? =>
_SignedPartialArithmetic.sub_partial[ISize](this, y)?

fun mul_partial(y: ISize): ISize ? =>
_SignedPartialArithmetic.mul_partial[ISize](this, y)?

fun div_partial(y: ISize): ISize ? =>
_SignedPartialArithmetic.div_partial[ISize, USize](this, y)?

fun mod_partial(y: ISize): ISize ? =>
_SignedPartialArithmetic.mod_partial[ISize, USize](this, y)?

fun divmod_partial(y: ISize): (ISize, ISize) ? =>
_SignedPartialArithmetic.divmod_partial[ISize, USize](this, y)?

primitive I128 is _SignedInteger[I128, U128]
new create(value: I128) => value
new from[A: (Number & Real[A] val)](a: A) => a.i128()
Expand Down Expand Up @@ -547,6 +655,24 @@ primitive I128 is _SignedInteger[I128, U128]
// doing
_SignedCheckedArithmetic._mulc[U128, I128](this, y)

fun add_partial(y: I128): I128 ? =>
_SignedPartialArithmetic.add_partial[I128](this, y)?

fun sub_partial(y: I128): I128 ? =>
_SignedPartialArithmetic.sub_partial[I128](this, y)?

fun mul_partial(y: I128): I128 ? =>
_SignedPartialArithmetic.mul_partial[I128](this, y)?

fun div_partial(y: I128): I128 ? =>
_SignedPartialArithmetic.div_partial[I128, U128](this, y)?

fun mod_partial(y: I128): I128 ? =>
_SignedPartialArithmetic.mod_partial[I128, U128](this, y)?

fun divmod_partial(y: I128): (I128, I128) ? =>
_SignedPartialArithmetic.divmod_partial[I128, U128](this, y)?

type Signed is (I8 | I16 | I32 | I64 | I128 | ILong | ISize)


Expand Down
Loading