1"""fontTools.misc.fixedTools.py -- tools for working with fixed numbers.
2"""
3
4from __future__ import print_function, division, absolute_import
5from fontTools.misc.py23 import *
6
7__all__ = [
8    "fixedToFloat",
9    "floatToFixed",
10]
11
12def fixedToFloat(value, precisionBits):
13	"""Converts a fixed-point number to a float, choosing the float
14	that has the shortest decimal reprentation.  Eg. to convert a
15	fixed number in a 2.14 format, use precisionBits=14.  This is
16	pretty slow compared to a simple division.  Use sporadically.
17
18	>>> fixedToFloat(13107, 14)
19	0.8
20	>>> fixedToFloat(0, 14)
21	0.0
22	>>> fixedToFloat(0x4000, 14)
23	1.0
24	"""
25
26	if not value: return 0.0
27
28	scale = 1 << precisionBits
29	value /= scale
30	eps = .5 / scale
31	digits = (precisionBits + 2) // 3
32	fmt = "%%.%df" % digits
33	lo = fmt % (value - eps)
34	hi = fmt % (value + eps)
35	out = []
36	length = min(len(lo), len(hi))
37	for i in range(length):
38		if lo[i] != hi[i]:
39			break;
40		out.append(lo[i])
41	outlen = len(out)
42	if outlen < length:
43		out.append(max(lo[outlen], hi[outlen]))
44	return float(strjoin(out))
45
46def floatToFixed(value, precisionBits):
47	"""Converts a float to a fixed-point number given the number of
48	precisionBits.  Ie. int(round(value * (1<<precisionBits))).
49
50	>>> floatToFixed(0.8, 14)
51	13107
52	>>> floatToFixed(1.0, 14)
53	16384
54	>>> floatToFixed(1, 14)
55	16384
56	>>> floatToFixed(0, 14)
57	0
58	"""
59
60	return int(round(value * (1<<precisionBits)))
61
62
63if __name__ == "__main__":
64    import doctest
65    doctest.testmod()
66