0

I am writing a graphing calculator in Python 3

However, this code here is giving me problems.

def domainGen(start,end,step):
    #generates a list of points for t, x, or theta to be equal to.
    #Acts like a floating point equivalent to "range" except it generates a whole list object, not just an iterator
    domain = [] #creates an empty list to store the domain
    minInt = start//step #rounding towards zero
    maxInt = end//step #rounding towards zero
    for n in range(minInt-1,maxInt + 1):
        if n*step >= start and n*step <= end:domain.append(n*step)
    return domain

The variables of this function are all user inputs and need to be floats or Decimal() values to allow for arbitrary precision.

However, when running this code I get a large number of floating point calculation errors, seemingly at random, to the numbers in the list "domain".

This is the output for domainGen(0,10,0.1):

[0.0, 0.1, 0.2, 0.30000000000000004, 0.4, 0.5, 0.6000000000000001, 0.7000000000000001, 0.8, 0.9, 1.0, 1.1, 1.2000000000000002, 1.3, 1.4000000000000001, 1.5, 1.6, 1.7000000000000002, 1.8, 1.9000000000000001, 2.0, 2.1, 2.2, 2.3000000000000003, 2.4000000000000004, 2.5, 2.6, 2.7, 2.8000000000000003, 2.9000000000000004, 3.0, 3.1, 3.2, 3.3000000000000003, 3.4000000000000004, 3.5, 3.6, 3.7, 3.8000000000000003, 3.9000000000000004, 4.0, 4.1000000000000005, 4.2, 4.3, 4.4, 4.5, 4.6000000000000005, 4.7, 4.800000000000001, 4.9, 5.0, 5.1000000000000005, 5.2, 5.300000000000001, 5.4, 5.5, 5.6000000000000005, 5.7, 5.800000000000001, 5.9, 6.0, 6.1000000000000005, 6.2, 6.300000000000001, 6.4, 6.5, 6.6000000000000005, 6.7, 6.800000000000001, 6.9, 7.0, 7.1000000000000005, 7.2, 7.300000000000001, 7.4, 7.5, 7.6000000000000005, 7.7, 7.800000000000001, 7.9, 8.0, 8.1, 8.200000000000001, 8.3, 8.4, 8.5, 8.6, 8.700000000000001, 8.8, 8.9, 9.0, 9.1, 9.200000000000001, 9.3, 9.4, 9.5, 9.600000000000001, 9.700000000000001, 9.8, 9.9]

I would like a function that can tell me the number of decimal places a user has specified their values to so that I can then round these numbers off to the same precision.

Is there a built in function that can help me?

If not, what is the most Pythonic way to solve this issue?

Notes:

I am aware there are perfectly good graph modules out there and want to do this myself as an exercise.

I have heard of the module "Decimal" but am not sure exactly how to use it and if it would help in this context.

Decimal Point precision is preferred but a decent workaround with Significant Figure precision could maybe be useful.

I am aware of this question but I understand why floating point errors occur, as I say, I need a function that tells me how many decimal points of precision a user has given me, so its not a duplicate.

20
  • round is a built in function, yes Commented Jul 9, 2018 at 12:25
  • Possible duplicate of Is floating point math broken? Commented Jul 9, 2018 at 12:26
  • I know how to round something to a known decimal point precision. What I need is a function that tells me to what precision a user input has been given. Commented Jul 9, 2018 at 12:27
  • 1
    int is completely pointless in minInt = int(start//step) since // already returns an int. Commented Jul 9, 2018 at 12:28
  • 1
    Now, are you trying to reinvent range here or what ? Commented Jul 9, 2018 at 12:34

1 Answer 1

1

If someone enters a float or int literal you could do something like this to it:

def get_float(s):
    if '.' in s:
        return float(s), len(s) - s.index('.') - 1
    else:
        return float(s), 0

This function returns a tuple consisting of the corresponding float and the number of characters after the decimal point. It would need to be modified if you want to properly handle float literals which include e or E.

For example:

>>> get_float('2')
(2.0, 0)
>>> get_float('2.1')
(2.1, 1)
>>> get_float('.001')
(0.001, 3)
>>> get_float('-0.001')
(-0.001, 3)

As a practical problem, is it really safe to assume that a user really just cares about 2 decimal places of accuracy because they entered '2.01' rather than '2.01000'? If you want to have a user-specified precision, why not have the user explicitly provide that precision?

Sign up to request clarification or add additional context in comments.

6 Comments

Thanks, I am not particularly up on my string functions yet. Implicit precision allows for a sleeker user interface but you may well be right :/
@Douglas The advantage of simply using the default float is that for the sort of things you do with a graphing calculator it gives more precision than the casual user requires. Using that precision in the internal calculations is a good way to mitigate round-off error. The above function could be used to record the user's precision but to use that strictly for formatting output. Just use the floats in the computations themselves.
Why would using this precision internally result in round off error when that's already what's happening?
I thought by forcing it to round to base 10 instead of base 2 it would make the calculations more accurate.
@Douglas If you do a complicated mathematical calculation and round to one decimal place after each step, pretty soon that one decimal place is no longer accurate. If you use 14-15 decimal places of accuracy (which is what a float does), then you could trust the first decimal place (and then some) even after thousands of computational steps. round() throws away information. If you throw away information, accuracy won't improve. Numerical analysis and round-off error is a deep topic. Naive uses of round() doesn't provide a reliable way to handle it.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.