version string issues
Martin Hosken
martin_hosken at sil.org
Wed Jul 15 16:23:15 CEST 2015
Dear All,
I've been looking at the version string in the name table and this is what it says:
Version string. Should begin with the syntax 'Version <number>.<number>' (upper case, lower case, or mixed, with a space between “Version” and the number).
The string must contain a version number of the following form: one or more digits (0-9) of value less than 65,535, followed by a period, followed by one or more digits of value less than 65,535. Any character other than a digit will terminate the minor number. A character such as “;” is helpful to separate different pieces of version information.
The first such match in the string can be used by installation software to compare font versions. Note that some installers may require the string to start with “Version ”, followed by a version number as above.
My assumption is that the aim here is to turn a 16.16 fixed point number as used in the head table into a string floating point representation. If this is the case then I don't think the above text meets the need. First of all consider the two numbers 0.10001 and 0.10002. These end up with the same 16.16 representation (0000199A). So I don't think the 65536 can represent the accuracy of the 16.16. Alternatively, what if we say that the 65536 just gets mapped as a number? Then, for example, 1.5 would map to 00010005, which is the floating point number 1.00009155. Which is not what we want. The only other alternative is to use Binary Coded Decimal but that can't handle more than 4 digits, so anything over 10000 is out. Therefore I suggest that the description here is wrong and we need something better.
What I think we want is some way to turn a 16.16 into what looks like a floating point number in decimal. While we could strive for purity and the full code space, we would end up with some pretty crazy numbers as per the example above of 1.000091552734375. Instead, I would like to suggest that a 16.16 can accurately represent a decimal floating point number with up to and including 4 decimal places and that we just go with that. Anything more and we risk all kinds of rounding problems. Thus we can store 1.1001 but not 1.10011 and so on. For those interested in the maths, I propose the following functions to do the conversion:
def asfixed(x : float) : return int(x * 65536)
def asfloat(x : int) : return float(int(float(x+1)/65536*10000))/10000
asfixed takes a floating point number with 1-4 decimal places, and asfloat takes a 32-bit number representing a 16.16 number and returns a floating point number with 0-4 decimal places (you'll have to sort out the .0 yourself!). The x+1 in the asfloat() sorts out any rounding issues given that all version numbers are positive and int() rounds down. For example asfixed(1.21) is 0x000135C2 whereas 0x000135C1 represents 1.2099.
I propose the following wording to replace the text in the standard:
Version string. Should being with the syntax 'Version <number>' (upper case, lower case or mixed, with a space between "Version" and the number).
The string must contain a version number that is a decimal less than 32768 that has 1-4 decimal places. Any character other than a digit will terminate the number. A character such as ";" is helpful to separate different pieces of version information.
The first such match in the string can be used by installation software to compare font versions. Note that some installers may require the string to start with “Version ”, followed by a version number as above.
The correspondance between the version number and the corresponding version number in the head table, is that the head version = int(number * 65536) and the number = float(int(float(head version + 1)/65536 * 10000))/10000
Yours,
Martin Hosken
More information about the mpeg-otspec
mailing list