If you opt-in, we use cookies to improve your experience on our site. Find out more.

# Bits and bytes

`bitsN`

datatype and bitwise operations.## Bits and bytes

Some notes on C’s integers

Some think, unsigned integers should be avoided .

For embedded this is not an option.

### Rename the exponentiation operator `^`

The exponention operator `^`

should be renamed to `**`

- maybe right associative.

Maybe it would be better to deprecate the exponentiation operator completely. A good argument for this change is given by the C# FAQ

With this change `^`

becomes available for the standard bitwise XOR (exclusive or) operation.

### Rename `uint`

to `nat`

Inspiration Motoko

Reason: `uint`

is not allowed to overflow and saturates in release code or panics in debug code.
The name `uint`

addresses the wrong association.
Therefore we should rename `uint`

to `nat`

NOTE: Maybe we should rename `bitsN`

to `wordN`

.
Those types occur only in 4 different sizes.
The name `bits`

might be associated with an arbitrary number.
Additional inspiration, a word
is a unit of data of a defined bit length.
Therefore we should rename `bits`

to `word`

.

### Allow a type annotation `:<type>`

for expressions

It is mainly needed for literals. It is consistent with type annotation in declarations.

IMPORTANT: This is not a cast or a conversion, but only a type annotation, to give literals different meanings.

### Eliminate `floatLiteral32`

Instead of using the specific `floatLiteral32`

we should use a type annotation.
With a type annotation any number literal can be used as a checked float literal.
This especially simplifies generic code.
Type annotation are anyway needed for binary, octal and hexadecimal literals.

By default a floatLiteral and hexFloatLiteral are of type `float64`

.

NOTE: Check that hexfloat literals are precise representations for their type.
NOTE: Maybe the default should be `float32`

for embedded systems?

Any `natLiteral`

can be annotated with a float type.
The range is checked, to get a precise float representation.

The following are all valid float literals.

```
(42: float64)
(42: float32)
(-17: float32)
(-1.2: float32)
42.0 // has type float64
(42.0: float32)
```

### Bit types

Bit types allow bitwise, relational, and arithmetic operators. Arithmetic operators wrap-around.

Different to `nat`

types which must not over- or underflow.

### Bitwise operators

Blech provides the standard set of bitwise operators known from C
.
Different to C these operators work on `bitsN`

types instead of unsigned `natN`

or signed `intN`

types.

#### Unary bitwise operator

For N = 8, 16, 32, 64

Bitwise negation: `~`

Type: `function (bitsN) returns bitsN`

#### Binary bitwise operators

More info on bitwise operations .

For N = 8, 16, 32, 64

Bitwise and: `&`

Bitwise or: `|`

Bitwise xor: `^`

Type: `function (bitsN , bitsN) returns bitsN`

#### Shift and rotate operators

Standard shift operators

shift left: `<<`

shift right: `>>`

Type: `function (bitsN, AnyNat) returns bitsN`

Additionally Blech should provide advanced shift operators

Arithmetic shift right: `+>>`

left rotate: `<<>`

right rotate: `<>>`

Type: `function (bitsN, AnyNat) returns bitsN`

These operators can be defined as Macros. If the macro has a suitable form, C compilers can translate circular shifts into one machine instruction. C compilers recognize the circular shift idiom .

The shift and rotate amount is a general unsigned integer type.
It is considered modulo the `bitsN`

width `N`

.

#### Arithmetic operators

As arithmetic types, `bitsN`

types implement numeric wrap-around (modulo `2**N`

).

#### Implicit conversion

Implicit conversion in C is complicated.

Implicit conversion is only allowed if no representation change is necessary.

`int8`

->`int16`

->`int32`

->`int64`

`float32`

->`float64`

`nat8`

->`nat16`

->`nat32`

->`nat64`

`bits8`

->`bits16`

->`bits32`

->`bits64`

IMPORTANT: The representation of `char`

is still not decided

#### Safe conversion using `as`

Conversion using the operator `as`

can be used for values.
That means:

- for right-hand side values
- for function input parameters
- for activity input parameters of simple type:
`intN`

,`natN`

,`bitsN`

,`floatN`

,`char`

Conversion with representation change is only allowed if no information is lost (has the same bit-size).

#### No subtyping for `bitsN`

types

Whenever

In general, this means that an expression of a more specific type may appear wherever an expression of a more general type is expected, provided the specific and general types are related by subtyping.

`bitsN`

types are in no subtype relation with each other.

`bitsN`

types are in no subtype relation with other arithmetic types.

### Literals

Binary, octal and hexadecimal literals have type `AnyBits`

.
Decimal literals have type `AnyInteger`

.

All literals of type `AnyBits`

need a type annotation in order to become an appropriate `bitsN`

type.

A type annotation can be ommited if an assignment determines the type.

For negative values of type `AnyInteger`

the two’s-complement representation is used to create the bits.

IMPORTANT: The two’s-complement representation for `intN`

is not mandatory in C.

```
let b1: bits8 = 0x1
let b2 = 0x1 : bits8
let b3 = (0x1 : bits8) << 2 // 0x4 as bits8
let b32 = 0x1A4: bits8 // type error not representable in bits8
let b4: bits8 = 255
let b5 = 255 : bits8
let b6: bits8 = -129 // type error, no representable as 2-complement in bits8
let b7 = -128: bits8 // ok
let b8 = (-50 - 150): bits8 // compile time error, not representable as 2-complement in bits8
```

### Use of operations

Bitwise operatorions and arithmetic operations cannot be applied to values of type `AnyBits`

.
Bitwise and arithmetic operations can only be applied to values of type `bitsN`

, that means the size has to be fixed before any operation.

```
let x: bits8 = -0x1 // type error size of `0x1` not known, for a suitable unary minus
let x = -(0x1: bits8) // ok, is (0xFF: bits8), by wrap around
```

### Hacker’s Delight translated to Blech

Hacker’s Delight is the definitive source of bitwise programming algorithms. It should be possible to use these hacks in Blech.

Turn off the rightmost 1-bit in a byte, producing 0 if none (e.g. 0b_0101_1000 => 0b_0101_0000, 0x_00 => 0x_00).

```
var x: bits8
x = x & (x - (1: bits8))
// or
x = x & (x - 0x_01)
```

Turn on the rightmost 0-bit in a word, producing all 1’s if none (e.g. 0x7AF3 => 0x7AF4, 0xFFFF => 0xFFFF).

```
var x: bits32
x = x | (x + (1: bits32))
// or
x = x | (x + 0b_1)
```