From: Kevin K. <ke...@ac...> - 2008-11-10 15:57:31
|
Alexandre Ferrieux wrote: [regarding pixelObjType and mmObjType] > - I cannot seem to find a documentation page giving the contracts > nor even rationale for these types. Something like "the unit is > sticky" or "no loss of precision while staying iso-unit", or the > like... I don't know all the history, but let me try to start from the other end. Tk, by design, tried very hard to keep all measurements in millimetres, because doing so had some chance at keeping more or less the same appearance of a GUI at all screen resolutions. Then as now, there was a problem otherwise that points, mm, and pixels were all freely intermixed; people would specify, say, the size of a text in points, but the size of the container that it went in in pixels (or vice versa), yielding proportions that were sometimes ludicrously bad (a microscopic label on a huge component, or worse, a label cut off by the borders of its component). This convention caused a lot of expense in the time when everything was a string in implementation as well as concept; screen measurements had to have their numeric parts scanned, their units recognized, and then be converted to mm. For this reason screen measurements were among the first Tk things to be converted to custom Tcl_Obj's. Since even the unit conversions were expensive (floating point dividers were *slow* in the early 1990's), objects representing both millimetres and pixels were implemented. These objects, like all Tcl objects, tended freely to shimmer. An object simply had whatever representation was requested last. At the time, little attention was paid to floating point accuracy. Tcl was slow enough that anyone doing serious numeric calculations resorted to C. It took quite a while to discover the subtle yet pernicious bugs that result when floating point conversion is not handled with full precision. (Situations where ($a != $b) while ($a eq $b) are nightmares. Such behaviour is acceptable only for NaN, and grudgingly so.) Those bugs led Don Porter and me to rework Tcl's floating point conversions, ensuring that the string and internal representations of 'double' objects always agree. (Tcl got bignums almost as a side effect. Bignum arithmetic was needed for the floating point calculations, so why not expose bignums at Tcl level too?) This effort stopped with Tcl. Don and I had a look at Tk, plucked a small amount of low-hanging fruit, and decided that neither of us really had the time to delve into how Tk uses and converts floating point numbers. I'm entirely unsurprised that there are remaining bugs. At the time that the screen measurement object types were implemented, people simply didn't care. I'm also convinced that the bugs are mostly benign; at the end of the calculation, they result in sub-pixel differences to screen objects. Where they do cause trouble is in applications where people need lossless conversion, expecting to get the same number out that they put in. Lossless conversion isn't possible or desirable in all cases, of course. Someone who, for example, scales an object on a canvas by a factor of 0.1 and then scales the result by 10.0 is not going to get the same object back. It's not going to happen. But for simple arithmetic on the screen metrics, it probably should. One possibility - I don't know how reasonable this would be - would be to carry screen dimensions over the lowest common denominator of points (or Microsoft's twentieths-of-points?), mm (or microns, perhaps?) and pixels. Such a representation would be an integer almost all of the time, perhaps yielding less chance of losing precision on the way. The key contract that Tcl tries to keep for numbers is: "If ($a eq $b), then ($a == $b) with the single exception of NaN." The chief objective of all the numeric changes in 8.5 was to make that statement true at long last. I would imagine that 'pixelObjType' and 'mmObjType', while they don't enter into == comparisons, need a similar contract about the internal representation matching the string. Tcl's numbers, since 8.5, achieve that in part by having internal representations that are sticky in the sense that if an object represents an integer, e.g. "123", Tcl_GetDoubleFromObj will cache the internal representation of an integer - not a double. The idea that "the unit is sticky" might be a means to that end. I know, I've made things less clear, not more -- but it's important to remember that some of these things Just Happened. -- 73 de ke9tv/2, Kevin |