blob: 59c55dd1d2d8290c9a483ce4efd76296c72441ee [file] [log] [blame]
Behdad Esfahbod2d67a182013-11-28 18:08:36 -05001"""fontTools.misc.fixedTools.py -- tools for working with fixed numbers.
2"""
3
Behdad Esfahbod1ae29592014-01-14 15:07:50 +08004from __future__ import print_function, division, absolute_import
Behdad Esfahbod2d67a182013-11-28 18:08:36 -05005from 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()