Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Designing numbering system with unsigned and signed ints

Tags:

scala

I'm trying to design a numbering system around both unsigned integers and signed integers. Both of these types have an underlying value that represents the number in Scala's number system. Here is the type hierarchy I have so far.

sealed trait Number {
  def + (num : Number) : Number = ???
  def - (num : Number) : Number = ???
  def * (num : Number) : Number = ???
}

sealed trait SignedNumber extends Number

sealed trait UnsignedNumber extends Number

sealed trait UInt32 extends UnsignedNumber {
  def underlying : Long
}

sealed trait UInt64 extends UnsignedNumber {
  def underlying : BigInt
}

sealed trait Int32 extends SignedNumber {
  def underlying : Int
}

sealed trait Int64 extends SignedNumber {
  def underlying : Long
}

I would like to define underlying in the trait Number so the compiler can enforce that underlying is defined in all of the children. However, the types for underlying vary for each trait - I want to keep the smallest possible type for each type. For instance, a UInt32 can be stored as a long in Scala, while a UInt64 needs to be stored as a BigInt.

What is the most effective way to do this?

like image 387
Chris Stewart Avatar asked Jun 05 '16 20:06

Chris Stewart


People also ask

Can signed and unsigned integers store the same number of values?

Both can store 256 different values, but signed integers use half of their range for negative numbers, whereas unsigned integers can store positive numbers that are twice as large.

What is the difference between signed and unsigned numbers?

A signed integer is a 32-bit datum that encodes an integer in the range [-2147483648 to 2147483647]. An unsigned integer is a 32-bit datum that encodes a nonnegative integer in the range [0 to 4294967295].

How are signed and unsigned integers stored with an example?

Signed and unsigned are those two ways. Since every integer can be identified using it's sign such as positive (+) or negative (-). On the other hand in an unsigned integer can not store negative values, only positive values can be stored in the unsigned variable. Example of signed integer: Sign int a = -4.

How do you use signed and unsigned?

Signed numbers use sign flag or can be distinguish between negative values and positive values. Whereas unsigned numbers stored only positive numbers but not negative numbers.


1 Answers

You can declare a type in the parent trait and override it in the subtraits.

sealed trait Number {
  type A
  def underlying: A
  def + (num : Number) : Number = ???
  def - (num : Number) : Number = ???
  def * (num : Number) : Number = ???
}

sealed trait SignedNumber extends Number

sealed trait UnsignedNumber extends Number

sealed trait UInt32 extends UnsignedNumber {
  override type A = Long
}

sealed trait UInt64 extends UnsignedNumber {
  override type A = BigInt
}

sealed trait Int32 extends SignedNumber {
  override type A = Int
}

sealed trait Int64 extends SignedNumber {
  override type A = Long
}

An example just to show use of the path-dependent type in case that isn't clear:

def getUnderlying(x: Number): x.A = x.underlying

To get the return types correct, I think another type might be required.

sealed trait Number {
  type A
  type B
  def underlying: A
  def +(that: B): B
}

sealed trait UInt32 extends Number { x =>
  override type A = Long
  override type B = UInt32
  override def +(y: B): B = new UInt32 {
    // todo - naive implementation, doesn't check overflow
    override val underlying = x.underlying + y.underlying
  }
}

def main(args: Array[String]) {
  print((
    new UInt32 { def underlying = 3 } +
    new UInt32 { def underlying = 4 }
  ).underlying)
}
like image 68
Chris Martin Avatar answered Oct 14 '22 23:10

Chris Martin