tellAboutX - Functions that expose the bits

Here are the different functions that tell us about the bits:

def tellAboutByte(x: Byte) =
  print("I am an 8-bit word that Scala views as having format 'Byte' ...\n"
        ++ "... my bits are, in binary, ("
        ++ new String((0 to 7)
                        .toArray
                        .map(j => (x >> 7-j)&1)
                        .flatMap(b => "%d".format(b)))
        ++ ")_2\n"
     ++ "... or equivalently, in hexadecimal, 0x%02X\n"
          .format(x)
     ++ "... Scala prints me out as " ++ x.toString ++ "\n"
     ++ "... I represent the signed decimal integer %d\n"
          .format(x)
     ++ "... I represent the unsigned decimal integer %d\n"
          .format(if (x & 0x80) != 0 then 0x100+x else x)
  )
end tellAboutByte

def tellAboutShort(x: Short) =
  print("I am a 16-bit word that Scala views as having format 'Short' ...\n"
     ++ "... my bits are, in binary, ("
        ++ new String((0 to 15)
                        .toArray
                        .map(j => (x >> 15-j)&1)
                        .flatMap(b => "%d".format(b)))
        ++ ")_2\n"
     ++ "... or equivalently, in hexadecimal, 0x%04X\n"
          .format(x)
     ++ "... Scala prints me out as " ++ x.toString ++ "\n"
     ++ "... I represent the signed decimal integer %d\n"
          .format(x)
     ++ "... I represent the unsigned decimal integer %d\n"
          .format(if (x & 0x8000) != 0 then 0x10000+x else x)
  )
end tellAboutShort

def tellAboutInt(x: Int) =
  print("I am a 32-bit word that Scala views as having format 'Int' ...\n"
     ++ "... my bits are, in binary, ("
        ++ new String((0 to 31)
                        .toArray
                        .map(j => (x >> 31-j)&1)
                        .flatMap(b => "%d".format(b)))
        ++ ")_2\n"
     ++ "... or equivalently, in hexadecimal, 0x%08X\n"
          .format(x)
     ++ "... Scala prints me out as " ++ x.toString ++ "\n"
     ++ "... I represent the signed decimal integer %d\n"
          .format(x)
     ++ "... I represent the unsigned decimal integer %d\n"
          .format(if (x & 0x80000000) != 0 then 0x100000000L+x else x)
  )
end tellAboutInt

def tellAboutLong(x: Long) =
  print("I am a 64-bit word that Scala views as having format 'Long' ...\n"
     ++ "... my bits are, in binary, ("
        ++ new String((0 to 63)
                        .toArray
                        .map(j => (x >> 63-j)&1)
                        .flatMap(b => "%d".format(b)))
        ++ ")_2\n"
     ++ "... or equivalently, in hexadecimal, 0x%016X\n"
          .format(x)
     ++ "... Scala prints me out as " ++ x.toString ++ "\n"
     ++ "... I represent the signed decimal integer %d\n"
          .format(x)
     ++ "... I represent the unsigned decimal integer %s\n"
          .format(if (x & 0x8000000000000000L) != 0 then BigInt("10000000000000000",16)+x else x)
  )
end tellAboutLong

def tellAboutChar(x: Char) =
  val xx = x.toShort
  print("I am a 16-bit word that Scala views as having format 'Char' ...\n"
     ++ "... my bits are, in binary, ("
        ++ new String((0 to 15)
                        .toArray
                        .map(j => (xx >> 15-j)&1)
                        .flatMap(b => "%d".format(b)))
        ++ ")_2\n"
     ++ "... or equivalently, in hexadecimal, 0x%04X\n"
          .format(xx)
     ++ "... Scala prints me out as " ++ x.toString ++ "\n"
     ++ "... indeed, my bits acquire meaning via the Unicode standard\n"
     ++ "    http://www.unicode.org/\n"
     ++ "... I represent a single 16-bit Unicode character '\\u%04X'\n"
          .format(xx)
     ++ "... as a signed decimal integer, I am %d\n"
          .format(xx)
     ++ "... as an unsigned decimal integer, I am %d\n"
          .format(if (x & 0x8000) != 0 then 0x10000+xx else xx)
  )  
end tellAboutChar

def tellAboutString(x: String) =
  val xx = x.toArray
  print("I am compound data that Scala views as having format 'String' ...\n"
     ++ "... in essence, I am a sequence of %d consecutive 16-bit words,\n"
          .format(xx.length)
     ++ "    each of which Scala views as having format 'Char'\n"
     ++ "... the bits of this sequence are, in binary, ("
        ++ new String(xx.flatMap(w => (0 to 15)
                                        .toArray
                                        .map(j => (w.toShort >> 15-j)&1)
                                        .flatMap(b => "%d".format(b))))
        ++ ")_2\n"
     ++ "... or equivalently, in hexadecimal, 0x%s\n"
          .format(new String(xx.flatMap(w => "%04X".format(w.toShort))))
     ++ "... Scala prints me out as " ++ x ++ "\n"
  )
end tellAboutString

def tellAboutFloat(x: Float) =
  val xx = java.lang.Float.floatToIntBits(x)
  val sign = (xx >> 31) & 0x1   // unpack sign
  val bexp = (xx >> 23) & 0xFF  // unpack biased exponent
  val tsig = xx & 0x007FFFFF    // unpack trailing significand
  val normalized = bexp > 0 && bexp < 254
  require(bexp < 254) 
   // (no support for telling about NaNs or infinities 
   //  -- consult the standard yourself for these!)

  // We are either normalized or subnormal at this point
  val exp = if normalized then bexp - 127  else  -126 
  val sig = if normalized then  (tsig | (1 << 23))  else tsig
  import java.math.{MathContext => jMC}
  def p2(j: Int): BigDecimal = if j < 0 then BigDecimal(1,jMC.UNLIMITED)/p2(-j) else BigDecimal(2,jMC.UNLIMITED).pow(j)
  val dd = ((0 to 23).filter(j => ((sig >> (23-j))&1) != 0).map(j => p2(exp-j)).foldLeft(BigDecimal(0,jMC.UNLIMITED))(_ + _)).toString
  val sigstr = new String((0 to 23).map(j => (sig >> (23-j))&1).flatMap(b => "%1d".format(b)).toArray)
  val bb = "(" ++ sigstr.take(1) ++ "." ++ sigstr.drop(1) ++ ")_2 * 2^{%d}".format(exp)
  val sdd = "%s%s".format(if sign == 1 then "-" else "",dd)
  val sbb = "%s%s".format(if sign == 1 then "-" else "",bb)
  print("I am a 32-bit word that Scala views as having format 'Float' ...\n"
     ++ "... my bits are, in binary, ("
        ++ new String((0 to 31)
                        .toArray
                        .map(j => (xx >> 31-j)&1)
                        .flatMap(b => "%d".format(b)))
        ++ ")_2\n"
     ++ "... or equivalently, in hexadecimal, 0x%08X\n"
          .format(xx)
     ++ "... Scala prints me out as " ++ x.toString ++ "\n"
     ++ "... indeed, my bits acquire meaning as specified\n"
     ++ "    in the binary interchange format 'binary32' in the\n"
     ++ "    IEEE Std 754-2008 IEEE Standard for Floating-Point Arithmetic\n"
     ++ "    http://dx.doi.org/10.1109%2FIEEESTD.2008.4610935\n"
     ++ "... this format is a bit-packed format with three components:\n"
     ++ "                            ("
        ++ new String((0 to 31)
                        .toArray
                        .map(j => (xx >> 31-j)&1)
                        .flatMap(b => "%d".format(b)))
        ++ ")_2\n"
     ++ "    a) the sign\n"
     ++ "       (bit 31):             %d\n".format(sign)
     ++ "    b) the biased exponent\n"
     ++ "       (bits 30 to 23):       "
        ++ new String((0 to 7)
                        .toArray
                        .map(j => (bexp >> 7-j)&1)
                        .flatMap(b => "%d".format(b)))
        ++ "\n"
     ++ "    c) the trailing significand\n"
     ++ "       (bits 22 to 0):                "
        ++ new String((0 to 22)
                        .toArray
                        .map(j => (tsig >> 22-j)&1)
                        .flatMap(b => "%d".format(b)))
        ++ "\n"
     ++ (
         if normalized then 
            "... my biased exponent %d indicates that I am a _normalized_ number\n".format(bexp)
            ++ "    with a leading 1-digit in my significand and\n"
            ++ "    an unbiased exponent %d = %d - 127\n".format(exp,bexp)
         else
            "... my biased exponent %d indicates that I am a _subnormal_ number\n".format(bexp)
            ++ "    with a leading 0-digit in my significand and\n"
            ++ "    an unbiased exponent %d\n".format(exp)
         )
     ++ "... that is, in _binary radix point notation_, I am exactly\n"
     ++ "                                  %s%s\n"
          .format(if sign == 1 then "" else " ",sbb)
     ++ "... or what is the same in _decimal radix point notation_, I am exactly\n"
     ++ "    %s\n".format(sdd)
  )
end tellAboutFloat

def tellAboutDouble(x: Double) =
  val xx = java.lang.Double.doubleToLongBits(x)
  val sign = ((xx >> 63) & 0x1L).toInt    // unpack sign
  val bexp = ((xx >> 52) & 0x7FFL).toInt  // unpack biased exponent
  val tsig = xx & 0x000FFFFFFFFFFFFFL     // unpack trailing significand
  val normalized = bexp > 0 && bexp < 2047
  require(bexp < 2047) 
   // (no support for telling about NaNs or infinities 
   //  -- consult the standard yourself for these!)

  // We are either normalized or subnormal at this point
  val exp = if normalized then bexp - 1023  else -1022 
  val sig = if normalized then (tsig | (1L << 52)) else tsig
  import java.math.{MathContext => jMC}
  def p2(j: Int): BigDecimal = { if(j < 0) { BigDecimal(1,jMC.UNLIMITED)/p2(-j) } else { BigDecimal(2,jMC.UNLIMITED).pow(j) } }
  val dd = ((0 to 52).filter(j => ((sig >> (52-j))&1) != 0).map(j => p2(exp-j)).foldLeft(BigDecimal(0,jMC.UNLIMITED) )(_ + _)).toString
  val sigstr = new String((0 to 52).map(j => (sig >> (52-j))&1).flatMap(b => "%1d".format(b)).toArray)
  val bb = "(" ++ sigstr.take(1) ++ "." ++ sigstr.drop(1) ++ ")_2 * 2^{%d}".format(exp)
  val sdd = "%s%s".format(if sign == 1 then "-" else "",dd)
  val sbb = "%s%s".format(if sign == 1 then "-" else "",bb)
  print("I am a 64-bit word that Scala views as having format 'Double' ...\n"
     ++ "... my bits are, in binary, ("
        ++ new String((0 to 63)
                        .toArray
                        .map(j => (xx >> 63-j)&1)
                        .flatMap(b => "%d".format(b)))
        ++ ")_2\n"
     ++ "... or equivalently, in hexadecimal, 0x%016X\n"
          .format(xx)
     ++ "... Scala prints me out as " ++ x.toString ++ "\n"
     ++ "... indeed, my bits acquire meaning as specified\n"
     ++ "    in the binary interchange format 'binary64' in the\n"
     ++ "    IEEE Std 754-2008 IEEE Standard for Floating-Point Arithmetic\n"
     ++ "    http://dx.doi.org/10.1109%2FIEEESTD.2008.4610935\n"
     ++ "... this format is a bit-packed format with three components:\n"
     ++ "                            ("
        ++ new String((0 to 63)
                        .toArray
                        .map(j => (xx >> 63-j)&1)
                        .flatMap(b => "%d".format(b)))
        ++ ")_2\n"
     ++ "    a) the sign\n"
     ++ "       (bit 63):             %d\n"
          .format(sign)
     ++ "    b) the biased exponent\n"
     ++ "       (bits 62 to 52):       "
        ++ new String((0 to 10)
                        .toArray
                        .map(j => (bexp >> 10-j)&1)
                        .flatMap(b => "%d".format(b)))
        ++ "\n"
     ++ "    c) the trailing significand\n"
     ++ "       (bits 51 to 0):                   "
        ++ new String((0 to 51)
                        .toArray
                        .map(j => (tsig >> 51-j)&1)
                        .flatMap(b => "%d".format(b)))
        ++ "\n"
     ++ (
         if normalized then
            "... my biased exponent %d indicates that I am a _normalized_ number\n".format(bexp)
            ++ "    with a leading 1-digit in my significand and\n"
            ++ "    an unbiased exponent %d = %d - 1023\n".format(exp,bexp)
         else
            "... my biased exponent %d indicates that I am a _subnormal_ number\n".format(bexp)
            ++ "    with a leading 0-digit in my significand and\n"
            ++ "    an unbiased exponent %d\n".format(exp)
         )
     ++ "... that is, in _binary radix point notation_, I am exactly\n"
     ++ "                                     %s%s\n"
          .format(if sign == 1 then "" else " ",sbb)
     ++ "... or what is the same in _decimal radix point notation_, I am exactly\n"
     ++ "    %s\n".format(sdd)
  )
end tellAboutDouble