On 02/09/2007 11:08 AM, Ron Jensen wrote: > I stripped the apply_mod() function out into its own small program for > analysis.
The experimental analysis confirms that the code is numerically unstable. I don't think there is any way to make it numerically stable. The instability can be swept under the rug, so that it does not affect cases of interest ... but anybody who takes the trouble to look closely will always be able to find it. > My conclusions: > - With bias set to 0.5 * (smallest expected step) both algorithms return > a correctly rounded result. > - With scroll set to 1e-6*step the original algorithm returns the same > result as your algorithm. > - With a very small error in property your algorithm returns a result > which is close to desired however the exact result varies with the input > error. While your algorithm returns acceptable results in the instant > case I can not be certain it will not fail in different cases. > - Your algorithm's output can be achieved with the current code, however > you algorithm can not always reproduce the current code's output. > > Therefore I recommend we stay with the current code and add either a > bias or scroll value to the xml files of the instruments which require > it. I come to slightly different conclusions. The main point of difference is that I think it would be better to change the code to establish a reasonable default <scroll> value, rather than rampaging through all the existing instruments to add <scroll> statements. Here's my reasoning, followed by my more-detailed conclusions: 1) First of all, the whole apply_mod() concept is delightful if we are trying to implement an analog "drum" type of readout, such as used on tach-hour meters, Hobbs-hour meters, and automobile odometers in the pre-electronic age. 2) In contrast, the apply_mod() concept is conspicuously unhelpful for digital readouts. 2a) For one thing, for an N-digit readout, it requires the user to write nearly the same code N times in the .xml file. This is laborious and error-prone at coding time, and inefficient at runtime. I doubt apply_mod() was ever intended for digital readouts. I suspect it was just pressed into service without much thought. Most particularly, I suspect it was never intended to be used with a zero <scroll> value. The <scroll> value is the answer to a question that should never get asked in the context of a digital display. Treating the kx165 display as an "animation" problem is absurd. You can "animate" a mechanical drum display. You don't "animate" the digits in a digital display. 2b) Secondly, it would be very hard to make the apply_mod() code numerically stable, except for integers as noted below. The fundamental problem is that it makes decisions on individual digits in isolation. Rounding decisions concerning the Nth digit are made in ignorance of decisions concerning lower-order digits. This is a deep-seated problem in the design. 3) The apply_mod() code works fine for integers. One way to make the currently-broken instruments work correctly would be to rewrite them to use integer kHz rather than fractional MHz. Note that 0.1 cannot be represented exactly in IEEE floating point. You are stuck with this fact; there is nothing you can do about it. According to my desk calculator, 1 - .1 - .1 - .1 - .1 - .1 - .1 - .1 - .1 - .1 - .1 = 1.38778e-16 In contrast, reasonable-sized integers can be represented exactly. 4) Converting a number to a decimal numeral is a "Comp Sci 101" homework problem. The solution in apply_mod() is emphatically not the textbook solution. 5) I see no reason why folks designing digital instruments should be required to provide a <scroll> value or a <bias> value at all. Such a requirement just creates usability problems for everybody forever and ever. Although it is possible to choose a <bias> value that solves the problem, this requires users to understand more about the problem than they should be required to understand. Documenting the proper usage of the <bias> parameter would not be pleasant. Sure, for any /particular/ case it is possible to find a <bias> that works, but it really doesn't capture the semantics of the overwhelming majority of cases. In most cases, the relevant meaning is more a notion of <precision>, such that the property will be rounded to the nearest multiple of the quantum of <precision> before further processing. The existing <scroll> parameter approximately (not exactly) captures the idea of precision. Therefore one wonders whether implementing and documenting new parameters would be worth the trouble. 6) It was not the goal of the new apply_mod() code to reproduce the same range of outputs as the old code. The goal was to unbreak the currently-broken instruments, without very much per-instrument fiddling. OTOH if you are curious to see how the two pieces of code "line up", try passing in -1 as the <scroll> value. 7) In addition to the horrific roundoff-related bugs, there are more subtle bugs in the instruments that need to be dealt with at some point. In particular, in a real KX165, if you start with a frequency of 122.975 and add 25 kHz with the small knob, you get 122.000, not 123.000; that is, the small digits do not "carry" into the big digits. (This is presumably a legacy from the ancient mechanical tuning mechanisms.) Tangential remark: Yet another issue that needs to be addressed is the case where a user types in something like 122.97 into the radio-setting dialog box. This needs to be channelized to 122.975 before further processing. ================= All in all, it seems to me that the reasonable options are: A) It would be nice to have some sort of sprintf facility, that would calculate N digits and put them on the display in one fell swoop. This would make the typical case much simpler and more convenient (compared to the current scheme that requires rewriting the same code for each digit). It would also be more numerically stable, allowing mutually-consistent roundoff decisions to be made for all digits. B) It should go without saying that we should keep apply_mod() around to handle the case of mechanical drum readouts. C) If people are desperate to preserve the existing <step> approach to encoding digits, rather than introducing a <bias> to solve the roundoff problem, the other options are: C1) It would make sense to recode everything to use integer kHz rather than fractional MHz. This would be no extra work, assuming we do it at the same time we address item (7) in the list above. This might require some extra code somewhere to convert kHz back to MHz, to interface with other code that is expecting frequencies in MHz ... but that would only need to be done in one place, not done N times for a N-digit readout. C2) The <bias> idea is not the worst idea I've ever seen, but I see no evidence that it is necessary. AFAICT, all the existing broken instruments can be unbroken by choosing a suitable nonzero <scroll> value. D) It is important to have reasonable defaults. A zero scroll value is not a reasonable default. If you don't like my expedient of setting the default scroll value to a millionth of the <step> size, another option would be to set it to 1e-6 in absolute units, in whatever units the <property> is being measured in. Either of these options suffices to unbreak the currently-existing broken instruments. In the future, anybody who comes up with an exceptional instrument for which the default doesn't work is free to pass in a non-default <scroll> value. ------------------------------------------------------------------------- Using Tomcat but need to do more? Need to support web services, security? Get stuff done quickly with pre-integrated technology to make your job easier. Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642 _______________________________________________ Flightgear-devel mailing list Flightgear-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/flightgear-devel