News:

Simutrans Wiki Manual
The official on-line manual for Simutrans. Read and contribute.

Problem with MakeObj

Started by AvG, July 23, 2011, 09:03:28 AM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

AvG

In my Holland-reality scenario I want to change revenues.
Passenger-revenue starting in 1750 with 0,01 Cr must change into 0,02 Cr in 1810.
Can't get that result.
In the .dat-file value=7 results in 0,01 Cr/km
                     value=8 results in 0,03 Cr/km
Can anyone explain this?
AvG
Ad van Gerwen

jamespetts

Yes - the per tile values in the .dat file have to be adjusted to per kilometre values in the game.
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.

AvG

The problem is NOT the tile or km.
The impossiblity to get 0,02 Cr/km is the problem. (0,01 and 0,03 are possible)
Maybe 2 rounding errors in MakeObj.
AvG
Ad van Gerwen

inkelyad

Make obj don't do any calculations. It just store value in
ware_besch_t::value

But revenue for 1km depends on other factors, see
goods_stats_t::zeichnen code.

Here is debug session for "value=8"

Breakpoint 4, goods_stats_t::zeichnen (this=0x870d498, offset=...) at gui/goods_stats_t.cc:51
(gdb) p wtyp->value
$16 = 8
(gdb) p wtyp->scaled_value
$17 = 2

That was "value=8" from pakfile and same value scaled to km/tile.

51 const sint64 base_price = (sint64)wtyp->get_preis();
(gdb) p base_price
$18 = 2
<it is same as scaled_value>
52 const sint64 min_price = base_price / 10ll;
(gdb) n
53 const sint64 speed_bonus_rating = (sint64)convoi_t::calc_adjusted_speed_bonus(wtyp->get_speed_bonus(), distance, welt);
(gdb) n
54 const sint64 base_bonus = base_price * (1000ll + ((sint64)bonus - 100ll) * speed_bonus_rating);
(gdb)
55 const sint64 revenue = (min_price > base_bonus ? min_price : base_bonus) * (sint64)distance;
(gdb)
56 sint64 price = revenue;
(gdb)
59 const uint16 journey_minutes = (((distance * 100) / welt->get_average_speed(way_type)) * welt->get_settings().get_meters_per_tile()) / 1667;
(gdb)
61 if(wtyp->get_catg_index() < 1)
(gdb)
64 const uint8 tolerable_comfort = convoi_t::calc_tolerable_comfort(journey_minutes, welt);
(gdb)
69 if(journey_minutes <=welt->get_settings().get_tolerable_comfort_short_minutes())
(gdb)
71 comfort_modifier = 20ll;
(gdb)
85 if(comfort > tolerable_comfort)
(gdb)
88 const uint8 max_differential = welt->get_settings().get_max_luxury_bonus_differential();
(gdb)
89 const uint8 differential = comfort - tolerable_comfort;
(gdb)
90 const sint64 multiplier = (welt->get_settings().get_max_luxury_bonus_percent() * comfort_modifier) / 100ll;
(gdb)
91 if(differential >= max_differential)
(gdb)
97 const sint64 proportion = (differential * 100) / max_differential;
(gdb)
98 price += (revenue * (sint64)(multiplier * proportion)) / 10000ll;

122 money_to_string( buf, price/300000.0 );
(gdb) p price
$19 = 8453
(gdb) p price/300000.0
$20 = 0.028176666666666666
(gdb)

And "0.028176666666666666" will be printed as "0.03"

AvG

Thanks inkelyad,
I am still a beginner in C++, so I can't understand this code.
What happens at value=7 ?
I change these values in the same save-file, so I think all influences are the same for value=7 and value=8
AvG
Ad van Gerwen

inkelyad

Quote from: AvG on July 24, 2011, 05:33:51 PM
I am still a beginner in C++, so I can't understand this code.
I don't understand it too. (Well, I don't understand the logic behind the code).
Quote
What happens at value=7 ?

goods_stats_t::zeichnen (this=0xc832d20, offset=...) at gui/goods_stats_t.cc:51
51 const sint64 base_price = (sint64)wtyp->get_preis();
(gdb) p wtyp->value
$1 = 7
(gdb) p wtyp->scaled_value
$2 = 1
(gdb) until 122
goods_stats_t::zeichnen (this=0xc832d20, offset=...) at gui/goods_stats_t.cc:122
122 money_to_string( buf, price/300000.0 );
(gdb) p price/300000.0
$3 = 0.014086666666666667


AvG, You operating on borderline precision. I suggest you scale all monetary values * 100.
0.01₵ will be one hundredth of 'cent'.

AvG

Thanks again inkelyad.
I understand your proposal to multiply by 100. That will cause problems in the future. My Pak will, when running in 1999, show prices for new items that are as near as possible to the real-world items.
Multiplying with 100 will take away the motivation for sorting out a lot of data.
But are we sure that math is OK in MakeObj ???
I tested and saw that values 2 till 7 all result in 0,01 Cr/km
Maybe you understand that I think there is some error in the MakeObj that makes from value=8 >> 0,03 Cr/km

It is also unacceptable for me to run my simulation for 40 years with a passenger-revenue that is 50% to high.
AvG
Ad van Gerwen

inkelyad

Quote from: AvG on July 24, 2011, 07:06:44 PM
I understand your proposal to multiply by 100. That will cause problems in the future. My Pak will, when running in 1999, show prices for new items that are as near as possible to the real-world items.
Multiplying with 100 will take away the motivation for sorting out a lot of data.
I don't understand this. How two extra digits can cause problem?
Quote
But are we sure that math is OK in MakeObj ???
Yes, there is no math in makeobj. All calculations happen in the main sumutrans program.

Quote
I tested and saw that values 2 till 7 all result in 0,01 Cr/km


value=2 to value=7
..
wtyp->value==2 to  wtyp->value==7
..
wtyp->scaled_value==0 to wtyp->scaled_value==1
..
base_price==0 to base_price==1
..etc

Loss of precision is inevitable here.

AvG

OK inkelyad, thanks again.
So the conclusion could be as follows:

As Simutrans is using small values like 0,05 Cr, the math of the combination of Simu.EXE and MakeObj should be capable of handling these values with adequate precision.
A jump in the math-result from 0,01 to 0,03 is NOT adequate precision.

Do you agree with this?
AvG
Ad van Gerwen

inkelyad

No, we are using two more numbers of precision because we want integer part to be precise. (And we still need to be careful. I am sure 28bpm setting will break precision somewhere).
It is impossible to have last digit precise in fixed-point arithmetic.
Compare
0.05/2 + 0.05/2 -> 0.02 + 0.02 -> 0.04
and
(0.05 + 0.05)/2 -> 0.1/2 -> 0.05