Re: Using ReplaceAll (/.) on numerical digits

*To*: mathgroup at smc.vnet.net*Subject*: [mg113268] Re: Using ReplaceAll (/.) on numerical digits*From*: David Bailey <dave at removedbailey.co.uk>*Date*: Thu, 21 Oct 2010 07:02:50 -0400 (EDT)*References*: <i9m854$jr5$1@smc.vnet.net>

On 20/10/10 09:10, Richard Klopp wrote: > Background: > I made some lab measurements and then calibrated the test instrument after > the fact. This changed the measurements slightly. I wanted to replace the > measurements with the calibrated values. The measurements were all very > close to 0.5600, only differing in the thousandths and ten-thousandths > places, so I coded my original data as a list of two-digit integers > {20,30,40}, then divided the whole list by 10000 and added 0.5600 to it. > > I found some seemingly weird behavior with ReplaceAll as shown below. Note > how 0.563 in data remains untouched while 0.562 and 0.564 get replaced as > intended, but when I simply type in 0.563 and do a replace, it gets replaced > successfully. Can someone explain why this happens? > > In any event, I've got a workaround based on StringReplace, which is likely > safer whether the weird behavior is a bug or a misunderstanding on my part. > > data = 0.5600 + 1/10000 {20, 30, 40} {0.562, 0.563, 0.564} (* 0.563 stays > untouched *) data /. {0.562 -> 0.5622, 0.563 -> 0.5637, 0.564 -> 0.5641} > {0.5622, 0.563, 0.5641} (* 0.563 stays untouched *) (0.5600 + 1/10000 {20, > 30, 40}) /. {0.562 -> 0.5622, 0.563 -> 0.5637, 0.564 -> 0.5641} {0.5622, > 0.563, 0.5641} (* 0.563 stays untouched *) {0.5600 + 20/10000, 0.5600 + > 30/10000, 0.5600 + 40/10000} /. {0.562 -> 0.5622, 0.563 -> 0.5637, 0.564 > -> 0.5641} {0.5622, 0.563, 0.5641} (* 0.563 gets replaced when typed in > directly *) {0.562, 0.563, 0.564, 0.5630} /. {0.562 -> 0.5622, 0.563 -> > 0.5637, 0.564 -> 0.5641} {0.5622, 0.5637, 0.5641, 0.5637} > > > (*workaround*) replaceDigits[numList_List, replacementDigitsList_List] := ToExpression[ StringReplace[ ToString[PaddedForm[#, {5, 5}]& /@ > numList], Map[ToString[PaddedForm[#, {5, 5}]]&, replacementDigitsList, > {2}] ] ] replaceDigits[data, {0.562 -> 0.5622, 0.563 -> 0.5637, 0.564 > -> 0.5641}] {0.5622, 0.5637, 0.5641} > The basic problem is that machine precision floating point quantities are not exact - several binary representations correspond to 0.5600, and ReplaceAll works on exact matches. One solution would be to convert your data to integers*10000, and work on those - converting them back later - but surely your re-calibration could be better represented as a function (maybe an interpolation) that should be applied to the data. David Bailey http://www.dbaileyconsultancy.co.uk