Tue, Nov 19, 10:24 AM CST

Renderosity Forums / Poser Python Scripting



Welcome to the Poser Python Scripting Forum

Forum Moderators: Staff

Poser Python Scripting F.A.Q (Last Updated: 2024 Sep 18 2:50 am)

We now have a ProPack Section in the Poser FreeStuff.
Check out the new Poser Python Wish List thread. If you have an idea for a script, jot it down and maybe someone can write it. If you're looking to write a script, check out this thread for useful suggestions.

Also, check out the official Python site for interpreters, sample code, applications, cool links and debuggers. This is THE central site for Python.

You can now attach text files to your posts to pass around scripts. Just attach the script as a txt file like you would a jpg or gif. Since the forum will use a random name for the file in the link, you should give instructions on what the file name should be and where to install it. Its a good idea to usually put that info right in the script file as well.

Checkout the Renderosity MarketPlace - Your source for digital art content!



Subject: Floating point decimals and binary representation.


structure ( ) posted Tue, 24 August 2021 at 2:40 AM · edited Tue, 19 November 2024 at 8:11 AM
Forum Coordinator

so using the following code I came across the "can't represent this decimal properly" feature.

I understand the reasoning for this, it has to do with the fact that decimals cannot be accurately represented by binary.

But lets say I need real precision ( for some engineering venture perhaps ). The results in blue are what I want, the results in red are what I am getting.

Is there a workaround in python to actually return the decimals I want?

from os.path import basename, dirname, exists, isfile, join, splitext
...
...
# make a new ( numbered ) copy of the original file
def uniquify( path, ext ):
    file_name = path
    if isfile(file_name):
        expand = 0
        while True:
            expand += round( .1, 2 ) 
            exp = "_" + str(expand)
            new_file_name = file_name.split(ext)[0] + str(exp) + ext
            if isfile(new_file_name):
                continue
            else:
                return new_file_name

image.png


changing the .1 to 1/10 yields the same result

image.png

similarly the following code returns odd numbers also.

import numpy
for i in numpy.arange( 0.1, 0.9, 0.1 ):
    print( i )

which returns

0.1
0.2
0.30000000000000004
0.4
0.5
0.6
0.7000000000000001
0.8

if I round the result:

for i in numpy.arange( 0.1, 0.9, 0.1 ):
    print( round( i, 2 ) )

python returns the following ...

0.1
0.2
0.3
0.4
0.5
0.6
0.7
0.8

EDIT : a temporary workaround seems to be slicing the returned number like this

new_file_name = file_name.split(ext)[0] + str(exp[0:4]) + ext

Locked Out


odf ( ) posted Tue, 24 August 2021 at 4:17 AM · edited Tue, 24 August 2021 at 4:17 AM

I'm not sure I understand the problem. If your application is to print version numbers, why represent them as floats, at all?

In general, to represent a number as a string rounded to a certain number of decimal places, say 3, you can use ("%.3f" % x).

for i in numpy.arange( 0.1, 0.9, 0.1 ):
  print("%.1f" % i)

-- I'm not mad at you, just Westphalian.


bagginsbill ( ) posted Tue, 24 August 2021 at 7:32 AM

We could literally answer your questions about goofy floats but first let's decide if that rabbit hole is worth ANY of the grief. I suggest instead that you deal with version strings using the dedicated, properly designed features of Python for this. Have a look.

https://packaging.pypa.io/en/latest/version.html


Renderosity forum reply notifications are wonky. If I read a follow-up in a thread, but I don't myself reply, then notifications no longer happen AT ALL on that thread. So if I seem to be ignoring a question, that's why. (Updated September 23, 2019)


bagginsbill ( ) posted Tue, 24 August 2021 at 7:34 AM

Oh crap. Right after I wrote that I discovered you have to install that "packaging" package and you might not be able to in Poser Python.


Renderosity forum reply notifications are wonky. If I read a follow-up in a thread, but I don't myself reply, then notifications no longer happen AT ALL on that thread. So if I seem to be ignoring a question, that's why. (Updated September 23, 2019)


bagginsbill ( ) posted Tue, 24 August 2021 at 7:46 AM · edited Tue, 24 August 2021 at 7:47 AM

OK so after a quick experiment I conclude your problem is simply that adding .1 each time is a bad way to do as the slight inaccuracy of representing .1 accumulates. Instead, just iterate on an integer and divide by 10.

Example:

for i in range(100):
    name = 'foo_copy_' + str(i/10) + '.bar'
    print(name)

Works just fine


Renderosity forum reply notifications are wonky. If I read a follow-up in a thread, but I don't myself reply, then notifications no longer happen AT ALL on that thread. So if I seem to be ignoring a question, that's why. (Updated September 23, 2019)


bagginsbill ( ) posted Tue, 24 August 2021 at 7:48 AM · edited Tue, 24 August 2021 at 7:48 AM

Honestly, though, I don't know why you need 0.1, 0.2, 0.3 ... instead of just 1, 2, 3 ...


Renderosity forum reply notifications are wonky. If I read a follow-up in a thread, but I don't myself reply, then notifications no longer happen AT ALL on that thread. So if I seem to be ignoring a question, that's why. (Updated September 23, 2019)


bagginsbill ( ) posted Tue, 24 August 2021 at 7:53 AM

I cleaned up your function - it can be much simpler.

# make a new ( numbered ) copy of the original file
def uniquify( path, ext ):
    file_name = path + ext
    i = 0
    while isfile(file_name):
        i += 1
        file_name = path + "_copy_" + str(i/10) + ext
    return file_name


Renderosity forum reply notifications are wonky. If I read a follow-up in a thread, but I don't myself reply, then notifications no longer happen AT ALL on that thread. So if I seem to be ignoring a question, that's why. (Updated September 23, 2019)


adp001 ( ) posted Tue, 24 August 2021 at 8:33 AM

bagginsbill posted at 8:28AM Tue, 24 August 2021 - #4425960

I cleaned up your function - it can be much simpler.

# make a new ( numbered ) copy of the original file
def uniquify( path, ext ):
    file_name = path + ext
    i = 0
    while isfile(file_name):
        i += 1
        file_name = path + "_copy_" + str(i/10) + ext
    return file_name

To make that work with Poser Versions != 12, you have to execute this first:

from __future__ import  division

If you don't you will get garbage with this function.

But, as @odf said: The better way is to use Pythons format functions to convert numbers to strings.




adp001 ( ) posted Tue, 24 August 2021 at 8:43 AM

Python 3 (Poser 12) understands the old way of formatting strings with "%", and Python 2 (P11) can handle ".format(...)" strings preferred with Python 3.

  • Python 2 string formatting: https://docs.python.org/2/library/stdtypes.html#string-formatting
  • Python 3 string formatting: https://docs.python.org/3/library/string.html#string-formatting




bagginsbill ( ) posted Tue, 24 August 2021 at 11:26 AM · edited Tue, 24 August 2021 at 11:29 AM

I'm not using Python 12 - but I am using Python 3 because 2 is dead.

Anyway - yes if you're in Python 2 (Poser 11 or below) then division by 10 needs to be i / 10.0.

And yes you can format umpteen ways

f'{i / 10:.1f}'
'%.1f' % (i / 10.0)
str(i / 10.0)

You pick which way you're comfortable with. I usually pick based on the simplest syntax, or the shortest amount of coding, which generally means fewer mistakes.


Renderosity forum reply notifications are wonky. If I read a follow-up in a thread, but I don't myself reply, then notifications no longer happen AT ALL on that thread. So if I seem to be ignoring a question, that's why. (Updated September 23, 2019)


adp001 ( ) posted Tue, 24 August 2021 at 2:35 PM

As far as I know, the forum is called "Python" and not "Python 3".

By the way, in the Poser universe there are significantly more Poser 11 users who need Python 2 than those who use Poser 12 with Python 3. And that's likely to continue for a while. As I see it, P12 will probably need another 3-5 years to become reasonably stable and usable. Which means Python 2 will continue to exist in the Poser universe....

Using Python standards (like format for displaying numbers) also has the advantage that there are less problems with conversions/changes. The current disaster regarding Python 3 incompatibility of most scripts should be incentive enough to do things differently in the future and stick to established standards.




odf ( ) posted Tue, 24 August 2021 at 6:35 PM

Thanks to this thread I learned that Python 3 has a decimal module.

-- I'm not mad at you, just Westphalian.


adp001 ( ) posted Tue, 24 August 2021 at 6:40 PM

https://docs.python.org/2.7/library/decimal.html

:) :) :)




odf ( ) posted Tue, 24 August 2021 at 6:41 PM

adp001 posted at 6:36PM Tue, 24 August 2021 - #4425963

bagginsbill posted at 8:28AM Tue, 24 August 2021 - #4425960

I cleaned up your function - it can be much simpler.

# make a new ( numbered ) copy of the original file
def uniquify( path, ext ):
    file_name = path + ext
    i = 0
    while isfile(file_name):
        i += 1
        file_name = path + "_copy_" + str(i/10) + ext
    return file_name

To make that work with Poser Versions != 12, you have to execute this first:

from __future__ import  division

If you don't you will get garbage with this function.

My preference is to use str(i / 10.0) which will work correctly in both Python 2 and 3. Similarly, I like to use the // in Python 2 because it won't break when one upgrades to 3.

-- I'm not mad at you, just Westphalian.


odf ( ) posted Tue, 24 August 2021 at 6:43 PM

adp001 posted at 6:42PM Tue, 24 August 2021 - #4426000

https://docs.python.org/2.7/library/decimal.html

:) :) :)

I didn't say that Python 2 didn't have it. It's just that the Python 3 manual was the first hit I found and I was too lazy to check if it was also available for Python 2.

-- I'm not mad at you, just Westphalian.


adp001 ( ) posted Tue, 24 August 2021 at 6:52 PM · edited Tue, 24 August 2021 at 6:53 PM

odf posted at 6:43PM Tue, 24 August 2021 - #4426001

My preference is to use str(i / 10.0) which will work correctly in both Python 2 and 3. Similarly, I like to use the // in Python 2 because it won't break when one upgrades to 3.

Yup, mine too. But it still makes more sense to write a formatted string like ... + "%1.1f" % [value] + ...




structure ( ) posted Tue, 24 August 2021 at 8:17 PM · edited Wed, 25 August 2021 at 12:19 AM
Forum Coordinator

Thanks for your feedback guys.

I have no intention of using flouting points in the example cited. I am actually using integers for that. However while writing the code for this I became curious as to how best to work with floating points. (I also tried the decimal module.)

I appreciate your responses.

p.s. @BagginsBill... Thanks for the tidy up

Locked Out


Privacy Notice

This site uses cookies to deliver the best experience. Our own cookies make user accounts and other features possible. Third-party cookies are used to display relevant ads and to analyze how Renderosity is used. By using our site, you acknowledge that you have read and understood our Terms of Service, including our Cookie Policy and our Privacy Policy.