# [CentralOH] Better Problem Description.

Louis Bogdan looiebwv at gmail.com
Tue Dec 10 00:59:01 CET 2013

```Hi Brian:  You bring up an interesting point. If num is 1.2399 would result
in 1.2300 my way.  In looking at that there is a real easy fix that also
simplifies the function as follows:
num = 1.2399
if num[-1] >7
num+=2     #this will make num 1.2398 ,1.2399 = 1.2400 or 1.2401.
elif num[-1]<3
num[-1]= 0      # this will make num 1.2401,1.2402 =1.2400
else:
num[-1] = 5    #nom 1.2394, 1.2395, 1.2396,1.2397 will =1.2395

I ran several "numbers" and found 2 occasions with a .0099 condition.  Does
this make any sense?
A num 1.2398 or 1.2399 would obviate the else statement but we do not have

On Mon, Dec 9, 2013 at 3:43 PM, Brian Costlow <brian.costlow at gmail.com>wrote:

> Louis,
>
> Here is a sort-of pythonic implementation of your algorithm. There's some
> non idiomatic stuff here because I think it's easier for a new Python
> person to follow. It takes a string which contains a representation of a
> decimal number as input. This will only give correct output if the number
> has four places to the right of the decimal. It will also have issues if
> the string passed in is not a number. And one more thing...read on
>
> # Used as a simple hash to lookup new last digit
> ROUNDING_LOOKUP = { '0':'0', '1':'0', '2':'0', '3':'5', '4':'5',
>     '5':'5', '6':'5', '7':'5', '8':'0', '9':'0', }
>
> def bogdan_round(num_as_string):
>     '''Round to 0.0005 step
>
>     Input must be a string representing a decimal number, with
>     four places to right of decimal. Anything else WILL break.
>     Negative values WILL NOT move in correct direction'''
>
>     # part that won't change, uses slice notation, given 1.2345 as input
> becomes 1.23
>     prefix = num_as_string[:-2]
>     # given 1.2345 becomes 4
>     next_to_last_digit = num_as_string[-2:-1]
>     # given 1.2345 becomes 5
>     last_digit = num_as_stringx[-1:]
>     next_to_last_as_int = int(next_to_last_digit)
>
>     if next_to_last_as_int > 7:
>         if next_to_last_as_int == 9:
>             next_to_last_digit = '0'
>         else:
>             next_to_last_digit = str(next_to_last_as_int + 1)
>     return prefix + next_to_last_digit + ROUNDING_LOOKUP[last_digit]
>
> Except there is a huge bug here.
>
> 1.2346 returns 1.2345
> 1.2349 returns 1.2350
> but
> 1.2399 returns 1.2300 NOT the correct 1.2400 which is what happens when
> you try to play with isolated digits as a string.
>
> To fix that requires traversing the rest of the string in a loop adjusting
> digits. It's better to do math. Returning to my earlier solution, with a
> couple of tweaks.
>
> All computers have imprecision when doing floating point math, because of
> precision limitations moving between decimal and the actual binary
> implementation of the numbers. This is not unique to Python, but any
> language that abstracts the idea of a float and targets multiple
> architectures.
>
> Python has a Decimal library that allows you to do fixed point decimal
> math, or do floating point that will notify you if precision is lost. This
> does the same as the above, plus it handles ints and floats as input,
> negative values:
>
> # Use the decimal lib
> from decimal import Decimal as D
>
> # Since we are rounding to closest 0.0005, we can't just use the quant
> method
> # but we have to multiply so we can do integer rounding then divide back
> MULTIPLIER = D('2000')
>
> # Number can be int, string, or in Python 2.7 or >, a float
> def custom_round(number):
>     number = D(number) # create a decimal type
>     # multiply so we can round to nearest int
>     adjusted_number = number * MULTIPLIER
>     # round, divide back, and return result in one step
>
> Here's the function in action, showing the result:
>
> >>> custom_round('1.2340')
> Decimal('1.234')
> >>> custom_round('1.2341')
> Decimal('1.234')
> >>> custom_round('1.2342')
> Decimal('1.234')
> >>> custom_round('1.2343')
> Decimal('1.2345')
> >>> custom_round('1.2344')
> Decimal('1.2345')
> >>> custom_round('1.2345')
> Decimal('1.2345')
> >>> custom_round('1.2346')
> Decimal('1.2345')
> >>> custom_round('1.2347')
> Decimal('1.2345')
> >>> custom_round('1.2348')
> Decimal('1.235')
> >>> custom_round('1.2349')
> Decimal('1.235')
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
> On Mon, Dec 9, 2013 at 12:56 PM, Louis Bogdan <looiebwv at gmail.com> wrote:
>
>> First off Brian, thank you for your interest in helping me.  So let's
>> start from the beginning.  The number comes from a keyboard input that is
>> requested with 4 decimal input and is modified with an imbedded formula.
>> In this application the keyboard number can vary from integer to integer
>> plus 4 decimal.  This modified number, "num", is used to control a stepper
>> motor where each step equals 0.0005" of linear motion.  My function rounds
>> "num" in such a manner that the maximum error is 0.0002", which in this
>> application is acceptable.  The initial number may be modified as much as
>> 30 times in a cycle.  These modifications are so handled that in
>> engineering parlance I "baseline" dimension rather that "chain" so that
>> each increment is within 0.0002" of true location rather than a possible
>> maximum accumulative error of 0.0066".  All that I can and have handled.
>> What I need is to put my "rounding" function into Python language. One
>> comment I received was to use only integers.  That would be no problem, we
>> would adjust the units and tens digit as necessary and accomplish the same
>> thing. It would be: motor steps equals num(decimal)/0.0005 or
>> num(integer)/5 as I have shown in one of my emails.  As far as the comment
>> of "other" accuracies can be totally ignored in the present discussion.
>>
>> Now I know that Python does rounding which I don't understand and have
>> not found any decent, understandable explanation how it does it.  I
>> understand rounding, even way back when I was proficient with the abacus.
>>
>> I hope this is some claification and if not, let me know.  Lou
>>
>>
>> On Mon, Dec 9, 2013 at 10:53 AM, Brian Costlow <brian.costlow at gmail.com>wrote:
>>
>>> Hi Louis,
>>>
>>> I read through all the group postings real quick this morning, and
>>> here's my take.
>>>
>>> What Jim is asking for (he's our resident elder curmudgeon, although in
>>> your case he could probably be your grandson.) is to step back and describe
>>> the problem in English.
>>>
>>> Python. That algorithm is best encoded in Python via string manipulation,
>>> which is not really what you should be doing if you are trying to do math.
>>>
>>> So, we want a generic description of the problem because we may find a
>>> better algorithm entirely.
>>>
>>> We also need to know where the input is coming from and where it is used
>>> after, because if you have floating point values coming in, and going out,
>>> then not only is string manipulation 'extra' work, it may bite you.
>>>
>>> Last, it's unclear whether the 0.0005 step value ever needs to change.
>>> Thus Jim's comment about magic numbers. I think your line that said this: "other
>>> accuracies can be obtained with positional variations" implies that 0.0005
>>> step might change and be some other value. But it's not clear.
>>>
>>> In my code I sent you earlier, 'custom_round' IS a subroutine (we
>>> usually say procedure or function in python-speak) that does exactly what
>>> you need. It doesn't do string manipulation, it does real math, but it will
>>> accept a string or any numeric type as input.
>>>
>>> You can also modify it so that the 0.0005 is changeable.There are a
>>> couple of design approaches to doing that, and the one you should use
>>> partly depends on the rest of your program design.
>>>
>>> Coding something in any language is not merely figuring a psuedo-code
>>> algorithm and then forcing the language to fit your algorithm.
>>>
>>> It's learning the idioms and built-in tools of the language.
>>>
>>>
>>>
>>>
>>>
>>>
>>>
>>>
>>>
>>>
>>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/centraloh/attachments/20131209/189831e9/attachment-0001.html>
```