6

In octave, all the numerical output subsequent to the command format bit will show the native bit representation of numbers as stored in the memory. For example,

octave:1> format bit
octave:2> 0.5
ans = 0011111111100000000000000000000000000000000000000000000000000000
octave:7> 2
ans = 0100000000000000000000000000000000000000000000000000000000000000
octave:3> format
octave:4> 0.5
ans = 0.50000

Is there an equivalent command in python to show all the numbers in their native-bit representation (so the output is as shown below)?

>>> "equivalent of the octave format bit command"
>>> 0.5
0011111111100000000000000000000000000000000000000000000000000000

(This is very different from the binary representation for 0.5.)

A.Apte
  • 105
  • 5
  • 1
    I doubt it; Python doesn't encourage knowing or caring where and how things are stored in memory. What do you want to do with it? – jonrsharpe Jul 21 '15 at 16:27
  • Related: [Binary representation of float in Python (bits not hex)](http://stackoverflow.com/q/16444726/953482). That's just for floats though. – Kevin Jul 21 '15 at 16:38
  • @Kevin thanks for the link but it was not quite what I was looking for. @jonsharpe I find it quite convenient, while teaching numerical analysis class, to use the `format bit` in octave to explain the floating point representation, normalized vs. denormalized floats, etc. But I would like to start using python for the class, hence the query. – A.Apte Jul 23 '15 at 03:52

2 Answers2

5

TL;DR; No, there is not Python equivalent

You are not supposed to need this information when you are using Python. Setting "output mode" like you did using octave is just not possible (without modifying Python itself). If you really want all outputs in other format than default, you could write custom function for that, and maybe even override default print function if you are using Python 3.

If you just want to see binary representation of number, you can use bin(number) function for integers. For floats you can use float.hex(number).

If we really want to see internal reprensentation, it requires some work, little bit of black magic and ctypes library. It is not easy (or anyhow usable) to get this data when using Python, but I created function that shows us how float is internally represented:

We know that floats in Python floats are IEEE 754 double precision floating point numbers, so they use 8 bytes (64 bits) of memory.

import ctypes

def show_float(x):
    asdouble = ctypes.c_double(x)
    xpointer = ctypes.addressof(asdouble)
    xdata = ctypes.string_at(xpointer, 8)
    print "".join([bin(ord(i))[2:] for i in xdata])

x = 3.14
show_float(x) # prints 1111110000101111010111010001101110001111010011000000

Integers are harder, because representation is not same in all implementations. You can find one example here.

Hannes Karppila
  • 969
  • 2
  • 13
  • 31
  • I only need this functionality to show the students the machine representation, so a function serves my purpose quite well (certainly better than "modifying Python"). Using your idea, I came up with functions which show exactly that I need (posted below), so thanks! – A.Apte Jul 23 '15 at 06:43
  • Unrelated question: what is TL;DR;? (Sorry, I am new to stackoverflow.) – A.Apte Jul 23 '15 at 07:55
1

Based on the answer by @Hannes Karppila, here are two functions which show the machine representation of any number in the binary and hex format. It uses essentially the same logic as that answer, but fills up the output with zeros to show the "correct" length for each byte.

import ctypes
import decimal
def print_as_octave_bit_hex(x):
  '''
  This function prints the binary representation as it would
  be printed using the format 'bit' and 'hex' in octave
  '''
  asdouble = ctypes.c_double(x)
  xpointer = ctypes.addressof(asdouble)
  xdata = ctypes.string_at(xpointer, 8)
  xbin= [(bin(i)[2:].zfill(8)) for i in xdata[-1::-1]]
  print(x, "=", x.hex(), "=", decimal.Decimal(x))
  print("representation in format 'bit' and 'hex' of octave")
  print("with spaces separating each byte")
  print(" ".join([i.zfill(8) for i in xbin]), "=",
        " ".join([hex(int(i,2))[2:].zfill(2) for i in xbin]))
  print("without spaces separating the bytes")
  print("".join([i.zfill(8) for i in xbin]), "=",
        "".join([hex(int(i,2))[2:].zfill(2) for i in xbin]))

def print_as_octave_native_bit_hex(x):
  '''
  This function prints the binary representation as it would
  be printed using the format 'native-bit' and 'native-hex' in octave
  '''
  asdouble = ctypes.c_double(x)
  xpointer = ctypes.addressof(asdouble)
  xdata = ctypes.string_at(xpointer, 8)
  xbin = [(bin(i)[2:].zfill(8)) for i in xdata]
  print(x, "=", x.hex(), "=", decimal.Decimal(x))
  print("representation in format 'native-bit' and 'native-hex' of octave")
  print("with spaces separating each byte")
  print(" ".join([(i.zfill(8))[-1::-1] for i in xbin]), "=",
        " ".join([hex(int(i,2))[2:].zfill(2) for i in xbin]))
  print("without spaces separating the bytes")
  print("".join([(i.zfill(8))[-1::-1] for i in xbin]), "=",
        "".join([hex(int(i,2))[2:].zfill(2) for i in xbin]))

x=1.1+2.2
print_as_octave_bit_hex(x)
print(" ")
print_as_octave_native_bit_hex(x)
3.3000000000000003 = 0x1.a666666666667p+1 = 3.300000000000000266453525910037569701671600341796875
representation in format 'bit' and 'hex' of octave
with spaces separating each byte
01000000 00001010 01100110 01100110 01100110 01100110 01100110 01100111 = 40 0a 66 66 66 66 66 67
without spaces separating the bytes
0100000000001010011001100110011001100110011001100110011001100111 = 400a666666666667

3.3000000000000003 = 0x1.a666666666667p+1 = 3.300000000000000266453525910037569701671600341796875
representation in format 'native-bit' and 'native-hex' of octave
with spaces separating each byte
11100110 01100110 01100110 01100110 01100110 01100110 01010000 00000010 = 67 66 66 66 66 66 0a 40
without spaces separating the bytes
1110011001100110011001100110011001100110011001100101000000000010 = 6766666666660a40
A.Apte
  • 105
  • 5