// 2 november 2017
package main

import (
	"fmt"
)

type fixed1616 uint32
type fixed214 uint16

func fixed1616To214(f fixed1616) fixed214 {
	f += 0x00000002
	g := int32(f) >> 2
	return fixed214(uint32(g) & 0xFFFF)
}

func (f fixed1616) In214Range() bool {
	base := int16((f >> 16) & 0xFFFF)
	return base >= -2 && base < 2
}

func (f fixed1616) String() string {
	base := int16((f >> 16) & 0xFFFF)
	frac := float64(f & 0xFFFF) / 65536
	res := float64(base) + frac
	return fmt.Sprintf("%f 0x%08X", res, uint32(f))
}

func (f fixed214) String() string {
	base := []int16{
		0,
		1,
		-2,
		-1,
	}[(f & 0xC000) >> 14]
	frac := float64(f & 0x3FFF) / 16384
	res := float64(base) + frac
	return fmt.Sprintf("%f 0x%04X", res, uint16(f))
}

func main() {
	fmt.Println(fixed214(0x7fff))
	fmt.Println(fixed214(0x8000))
	fmt.Println(fixed214(0x4000))
	fmt.Println(fixed214(0xc000))
	fmt.Println(fixed214(0x7000))
	fmt.Println(fixed214(0x0000))
	fmt.Println(fixed214(0x0001))
	fmt.Println(fixed214(0xffff))

	fmt.Println()

	for i := uint64(0x00000000); i <= 0xFFFFFFFF; i++ {
		j := fixed1616(i)
		if !j.In214Range() { continue }
		fmt.Println(j, "->", fixed1616To214(j))
	}
}