• Our friends from AlphaCentauri2.info are in need of technical assistance. If you have experience with the LAMP stack and some hours to spare, please help them out and post here.

Python Round woes.

Goombaz

Warlord
Joined
Sep 11, 2005
Messages
297
I am messing around with the python and so far, I have achieved the result I wanted. I modified the basic year display to display CurrentTurn/MaxTurns and the year instead of just the year.

In addition to this, I am trying to make it display the percentage of the game that has elapsed. This is the code in-total for what I have done so far.

This is in the CvMainInterface.py file(well, a copy of it in my mod directory anyhow).

g_szTimeText = unicode(gc.getGame().getGameTurn()+1) + "/" + unicode(gc.getGame().getMaxTurns()) +" " + unicode(round(100*((1.00*(gc.getGame().getGameTurn()+1)) / gc.getGame().getMaxTurns())),2) + "% " + unicode(CyGameTextMgr().getInterfaceTimeStr(ePlayer))

I know, it is horribly messy.

This is the part I am concerned with:

unicode(round(100*((1.00*(gc.getGame().getGameTurn()+1)) / gc.getGame().getMaxTurns())),2)

It works fine if I type it as:

unicode((100*((1.00*(gc.getGame().getGameTurn()+1)) / gc.getGame().getMaxTurns())))

or as:

unicode(int(100*((1.00*(gc.getGame().getGameTurn()+1)) / gc.getGame().getMaxTurns())))

The problem is, however, that the former has like a 10 digit decimal and looks way too ugly, and the latter isn't quite as fine as I wanted, as whole percentages aren't helpful, and I don't like the idea of 2.99% being shown as 2%. When I attempt to do the round-to-two places as I show above, it simply no longer prints the line to the screen at all...

Does anyone have any idea why it renders it unprintable?
 
:bump:

Sorry this has been moved/buried so I thought I would bump it once for another go at an answer. I realize I could check a bunch of python references directly, but this is really all I want right at the moment so a direct, simple answer would be preferred.
 
Goombaz said:
This is the part I am concerned with:

unicode(round(100*((1.00*(gc.getGame().getGameTurn()+1)) / gc.getGame().getMaxTurns())),2)

It works fine if I type it as:

unicode((100*((1.00*(gc.getGame().getGameTurn()+1)) / gc.getGame().getMaxTurns())))

or as:

unicode(int(100*((1.00*(gc.getGame().getGameTurn()+1)) / gc.getGame().getMaxTurns())))

The problem is, however, that the former has like a 10 digit decimal and looks way too ugly, and the latter isn't quite as fine as I wanted, as whole percentages aren't helpful, and I don't like the idea of 2.99% being shown as 2%. When I attempt to do the round-to-two places as I show above, it simply no longer prints the line to the screen at all...

Does anyone have any idea why it renders it unprintable?

No clue. Though you could enable logging and then print out what that is using CvUtil.pyPrint. Just to see if it's actually calculating it correctly. Also, why are you multiplying by 1.00? To convert to float? If so, why not use the float() function?

Req
 
Goombaz said:
unicode(round(100*((1.00*(gc.getGame().getGameTurn()+1)) / gc.getGame().getMaxTurns())),2)

Well, unless you've typed it out differently here than in the script, it's merely a () problem.

Ie, this should work:
unicode(round(100*((1.00*(gc.getGame().getGameTurn()+1)) / gc.getGame().getMaxTurns()), 2))

Bh
 
When I made the change you suggested Bhuric, for some reason that I can't fathom it goes back to the 10ish place decimals :/
 
Not only does it show a weird result (~10 decimals), it shows a wrong one too!
Try unicode(round(1.1111, 2))

The result for me is 1.11000001431
 
Well, a cheap way to get around the problem is to multiply the number by 100, change it to an int, then divide it by 100.

Bh
 
I actually tried that already Bhuric. Oddly enough dividing it by 100 results in a really really long number even AFTER it was chopped into a pure INT before dividing. It looks like it STARTS to work alright, like you get 1.25ish, but it is instead something like 1.25000000001441 or 1.249999999991441. It's like it's not *quite* accurate.

I honestly think Civ 4 python has some kind of deep-seated floating point issue. Like there is some kind of garbage in the numbers you can't quite get past. I really hope I am being naive about this, because if that is the case it could be a nasty bug. I will go back and try that cheap solution again, I am fairly sure it won't work as I already tried it but perhaps the exact numbers involved would provide insight into the nature of the problem.
 
Ok, here is the latest on the problem. I have posted the code I used to compute the percentage as well as a column of results showing the problem in detail in a real use scenario. I hope that perhaps this will be detailed enough to lead to a fix or a workaround. This is the code as per Bhurics suggestion and the unfortunate result.

unicode((int(10000*(float(gc.getGame().getGameTurn()) / gc.getGame().getMaxTurns())))/100.0)

is the code used.

This is the result generated.



Click thumbnail for detailed info.

The essence of the problem seems to be the "trailing junk" that seems to result when dividing.
 
This may sound odd but... have you had anyone else test your code on another system to make sure it duplicates the issue for them?

also, i know it's tricky to work with but try pumping the numbers through a short script that mimics what's going on in Civ4, in the Python environment and run it (without Civ4) in IDLE/debug mode.

The reason i ask about trying it on another system is that there is still an occasional processor out there with the FLOP bug that Intel was notoriuos for in the older P3 line. The issue you are having is similar to that bug (but more frequent/reproducable than the hardwre FLOP bug... I doubt it's actually the case...)
 
That is a good point. I will go grab the Python environment and fire it up.

Tell you what, I will post the buggy version and see if you get the same result. Anyone who wants to is invited to give it a go and report back to me. If it IS a bug with Civ 4 Python specifically it could be important to get the word out, or at least find a workaround.

If you (or anyone else reading this) feel like it download this version, fire it up, and tell me what you get.

Also it is entirely possible that I am just a fool. Don't keep me hanging if I have made a downright stupid mistake.
 

Attachments

Ok situation update. I put this through IDLE on python 2.4.2

>>> unicode((int(10000*(float(19) / 440)))/100.0)
u'4.31'

and this corresponds to the result for turn 19/440, which was

4.30999994278

which I think you will agree, is extremely close to 4.31.

So for whatever reason the python within Civ 4 is not accurate with decimals.

Can anyone more qualified than me (I am an intermediate programmer, but *very* new to Python) confirm or disconfirm this problem specific to Civ 4 Python? IDLE is rounding correctly, Civ 4 is not. Or I am doing something wrong I suppose:crazyeye:
 
Maybe i'll post what I did to the file... Now im getting 2%, 4%, 6% 9%!!!!!!

Here: g_szTimeText = unicode(gc.getGame().getGameTurn()) + "/" + unicode(gc.getGame().getMaxTurns()) +" " + unicode((int(1000*(float(gc.getGame().getGameTurn()) / gc.getGame().getMaxTurns())))/1.0) + "%" + unicode(CyGameTextMgr().getInterfaceTimeStr(ePlayer))

This new one is...perfect they are all whole numbers wooohoooo!!!!(um... just check to make sure so i dont embaress myself...) Just replace this with what you have and check if its the right scale and whatever stuff you need.
 
While I appreciate the effort, I already got that to work. The versions that I have up in the actual modpack thread work this way. Thank you for the attempt to help, however :)

My current effort is to allow 2 decimal digits, which is not that much more clutter visually and allows for a much finer sense of the passage of time.
 
Back
Top Bottom