memconv

package
v0.0.0-...-948650a Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 25, 2024 License: MIT Imports: 1 Imported by: 0

Documentation

Overview

Package memconv implements "type punning" of raw memory, reinterpreting one type's representation as another. Note that this is *pointer* type conversion, not human-intuitive type conversion: for example, a float64 reinterpreted as a uint64 would simply expose the IEEE-75 floating-point representation.

Example
// Reimplementation of
// https://github.com/id-Software/Quake-III-Arena/blob/dbe4ddb10315479fc00086f08e25d968b4b43c49/code/game/q_math.c#L552C1-L552C1
// with original comments for the lolz.
quakeInverseSqrt := func(number float32) float32 {
	x2 := number * 0.5
	y := number

	i := CastPtr32[float32, int32](&y) // evil floating point bit level hacking
	*i = 0x5f3759df - (*i >> 1)        // what the fuck?

	for j := 0; j < 3; j++ {
		y *= 1.5 - (x2 * y * y) // jth iteration
	}

	return y
}

for _, x := range []float32{2, 3, 4, 1. / 9.} {
	fmt.Printf("%.3f => %.6f vs %.6f\n", x, quakeInverseSqrt(x), 1/math.Sqrt(float64(x)))
}
Output:

2.000 => 0.707107 vs 0.707107
3.000 => 0.577350 vs 0.577350
4.000 => 0.500000 vs 0.500000
0.111 => 3.000000 vs 3.000000

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func Cast

func Cast[From B64, To B64](x *From) To

Cast is equivalent to CastPtr but it returns a copy.

Example
posInt := int64(42)
posUint := Cast[int64, uint64](&posInt)
negInt := -posInt

const format = "%[1]T %#9[1]b => %[2]T %#064[2]b"
fmt.Printf(format+"\n", posInt, posUint)
fmt.Printf(format+" (two's complement)\n\n", negInt, Cast[int64, uint64](&negInt))

// Note that, unlike CastPtr(), this only changes posInt as posUint is a
// copy.
posInt++
fmt.Printf("%[1]T %[1]d != %[2]T %[2]d (copy unless using CastPtr())\n\n", posInt, posUint)

oneFP := 1.
fmt.Printf("%[1]T %.3[1]f => %[2]T %#064[2]b (IEEE-754 representation)\n", oneFP, Cast[float64, uint64](&oneFP))
Output:

int64  0b101010 => uint64 0b0000000000000000000000000000000000000000000000000000000000101010
int64 -0b101010 => uint64 0b1111111111111111111111111111111111111111111111111111111111010110 (two's complement)

int64 43 != uint64 42 (copy unless using CastPtr())

float64 1.000 => uint64 0b0011111111110000000000000000000000000000000000000000000000000000 (IEEE-754 representation)

func Cast32

func Cast32[From B32, To B32](x *From) To

Cast32 is the 32-bit equivalent of Cast().

func CastPtr

func CastPtr[From B64, To B64](x *From) *To

CastPtr returns x, interpreted as a pointer to a different type, using the same underlying memory; i.e. a change to the value pointed to by the incoming pointer will result in a change to the value pointed to by the returned pointer, and vice versa.

Example
posInt := int64(42)
posUint := CastPtr[int64, uint64](&posInt)

// Note that this changes both posInt and posUint because they share the
// same underlying memory.
posInt++
fmt.Printf("%[1]T %[1]d => %[2]T %[2]d (shared memory on increment)\n", posInt, *posUint)
Output:

int64 43 => uint64 43 (shared memory on increment)

func CastPtr32

func CastPtr32[From B32, To B32](x *From) *To

CastPtr32 is the 32-bit equivalent of CastPtr().

Types

type B32

type B32 interface {
	~int32 | ~uint32 | ~float32 | ~[4]byte
}

A B32 is a contiguous region of 32 bits.

type B64

type B64 interface {
	~int64 | ~uint64 | ~float64 | ~complex64 | ~[8]byte
}

A B64 is a contiguous region of 64 bits.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL