News:

Simutrans Forum Archive
A complete record of the old Simutrans Forum.

Weird format specifier problem with 64-bit variables

Started by jamespetts, March 29, 2009, 08:16:34 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

jamespetts

One of the updates to the latest version of Simutrans-Experimental is to use a signed 64-bit integer instead of an unsigned 32-bit integer to represent "ticks": the smallest units of time recognised by Simutrans. The reasoning behind this is that Simutrans-Experimental uses ticks to measure timekeeping accurately for a number of its new features. If an unsigned 32-bit integer were used, and a player were to have a very long game (approx. 300 years - highly unlikely, but not unknown: I have seen examples on this forum), the value would eventually overflow, and mess up all the timings.

I have successfully changed the values to 64-bit, including in loading and saving, but have one remaining problem: the time no longer displays correctly in the GUI. Instead of the hours going all the way through the day, it reaches twenty-past midnight or so, and turns to the next day. The minutes pass much more slowly than they did before, and are supposed to do. Initially, I thought that the problem was with some low-level means of calculating the time, and that there was some bit-twiddling going on somewhere, but that is not so: when I look at the values with a debugger, they appear correct: only the display is wrong. I had the same problem when I tried to display the value of "ticks" itself - it would get to about 50 or so, and just go back to 0.

The oddest part of it is that the minutes and hours (which show as being correct in the debugger) are not themselves 64-bit variables, but 32-bit variables. Does anyone have the first clue what is going on?
Download Simutrans-Extended.

Want to help with development? See here for things to do for coding, and here for information on how to make graphics/objects.

Follow Simutrans-Extended on Facebook.

gerw

Maybe the problem is bit shifting? It works different with signed/unsigned integers (at least if the signed one is really negative).

Happens this also with unsigned 64 bit integers?

jamespetts

I could not get unsigned 64bit integers to work properly, since there is no way of saving them: the only save method written for 64-bit integers requires a signed type. And I cannot find any bit shifting in relation to the code for displaying the month, although perhaps I have missed something.

The relevant code snippet is here:


sint64 ticks=1, month=0, year=0;

const ding_t *dt = wl->get_zeiger();
pos = dt->get_pos();
month = wl->get_last_month();
year = wl->get_last_year();
ticks = wl->get_zeit_ms();

// calculate also days if desired
const sint64 ticks_this_month = ticks % wl->ticks_per_tag;
uint32 tage, stunden, minuten;
if(umgebung_t::show_month>1) {
static sint32 tage_per_month[12]={31,28,31,30,31,30,31,31,30,31,30,31};
tage = ((ticks_this_month*tage_per_month[month]) >> wl->ticks_bits_per_tag) + 1;
stunden = ((ticks_this_month*tage_per_month[month]) >> (wl->ticks_bits_per_tag-16));
minuten = (((stunden*3) % 8192)*60)/8192;
stunden = ((stunden*3) / 8192)%24;
}
else {
tage = 0;
stunden = (ticks_this_month * 24) >> wl->ticks_bits_per_tag;
minuten = ((ticks_this_month * 24 * 60) >> wl->ticks_bits_per_tag)%60;
}

char time [128];
char info [256];
char stretch_text[256];
char delta_pos[64];

//DBG_MESSAGE("umgebung_t::show_month","%d",umgebung_t::show_month);
// @author hsiegeln - updated to show month
// @author prissi - also show date if desired
switch(umgebung_t::show_month) {
// german style
//#ifdef DEBUG
// case 4: sprintf(time, "%s, %d %s %d %d:%02dh TICKS: %li",
//#else
case 4: sprintf(time, "%s, %d %s %d %u:%02uh",
//#endif
translator::translate(seasons[wl->get_jahreszeit()]), //Season
tage, //Day
translator::get_month_name(month%12), //Month
year,
stunden, //"Hours" (Google)
//#ifdef DEBUG
// minuten, //Minutes
// ticks
//#else
minuten //Minutes
//#endif
);
break;
// us style
case 3: sprintf(time, "%s, %s %d %d %2d:%02d%s",
translator::translate(seasons[wl->get_jahreszeit()]),
translator::get_month_name(month%12),
tage,
year,
stunden%12,
minuten,
stunden<12 ? "am":"pm"
);
break;
// japanese style
case 2: sprintf(time, "%s, %d/%s/%d %2d:%02dh",
translator::translate(seasons[wl->get_jahreszeit()]),
year,
translator::get_month_name(month%12),
tage,
stunden,
minuten
);
break;
// just month
case 1: sprintf(time, "%s, %s %d %2d:%02dh",
translator::get_month_name(month%12),
translator::translate(seasons[wl->get_jahreszeit()]),
year,
stunden,
minuten
);
break;
// just only season
default: sprintf(time, "%s %d",
translator::translate(seasons[wl->get_jahreszeit()]),
year);
break;
}
Download Simutrans-Extended.

Want to help with development? See here for things to do for coding, and here for information on how to make graphics/objects.

Follow Simutrans-Extended on Facebook.

prissi

If wl->ticks_per_tag then there might be already an overflow in this place ...

jamespetts

Prissi,

thank you for your reply :-) I'm not sure where the overflow would be: I have made wl->ticks_per_tag a sint64, too. Or am I misunderstanding something...?
Download Simutrans-Extended.

Want to help with development? See here for things to do for coding, and here for information on how to make graphics/objects.

Follow Simutrans-Extended on Facebook.

prissi

Hard to guess; step by step through the code should tell. Mostly it is from shifts when the highest bit is set, because then unexpectend numbers will be the result; but this should be fine.