PC [BUG] Rounding Error when Calculating Time for Crop to Grow

Babborino

Newcomer
So I was trying to figure out why a yam takes 8 days to grow with agriculturalist instead of 9 days, and I came across the following code from https://github.com/veywrn/StardewVa...0a83/StardewValley/TerrainFeatures/HoeDirt.cs:

C#:
protected void applySpeedIncreases(Farmer who)
{
    if (crop == null)
    {
        return;
    }
    bool paddy_bonus = false;
    if (currentLocation != null && paddyWaterCheck(currentLocation, currentTileLocation))
    {
        paddy_bonus = true;
    }
    if (!(((int)fertilizer == 465 || (int)fertilizer == 466 || (int)fertilizer == 918 || who.professions.Contains(5)) | paddy_bonus))
    {
        return;
    }
    crop.ResetPhaseDays();
    int totalDaysOfCropGrowth = 0;
    for (int j = 0; j < crop.phaseDays.Count - 1; j++)
    {
        totalDaysOfCropGrowth += crop.phaseDays[j];
    }
    float speedIncrease = 0f;
    if ((int)fertilizer == 465)
    {
        speedIncrease += 0.1f;
    }
    else if ((int)fertilizer == 466)
    {
        speedIncrease += 0.25f;
    }
    else if ((int)fertilizer == 918)
    {
       speedIncrease += 0.33f;

   }
    if (paddy_bonus)
    {
        speedIncrease += 0.25f;
    }
    if (who.professions.Contains(5))
    {
        speedIncrease += 0.1f;
    }
    int daysToRemove = (int)Math.Ceiling((float)totalDaysOfCropGrowth * speedIncrease);
    int tries = 0;
    while (daysToRemove > 0 && tries < 3)
    {
        for (int i = 0; i < crop.phaseDays.Count; i++)
        {
            if ((i > 0 || crop.phaseDays > 1) && crop.phaseDays != 99999)
            {
                crop.phaseDays--;
                daysToRemove--;
            }
            if (daysToRemove <= 0)
            {
                break;
            }
        }
        tries++;
    }
}
Apparently, C# floating point arithmetic/rounding is such that 10.0f * 0.1f > 1, that is, the following code outputs True, as one can check here:

C#:
using System;
class HelloWorld {
  static void Main() {
      Console.WriteLine(10f * 0.1f > 1);
  }
}
What this means is that
Code:
int daysToRemove = (int)Math.Ceiling((float)totalDaysOfCropGrowth * speedIncrease);
results in
Code:
int daysToRemove = (int)Math.Ceiling(10.0f * 0.1f);
which rounds up to 2 since 10.0f * 0.1f > 1. I'd like to note that this can be avoided with the following pseudocode, which deals only in integer division by considering the percentage as an integer, and then integer-dividing by 100 afterwards and adds 1 if there is a remainder (effectively rounding up):

Code:
int speedIncrease = 0
if (using speed-gro):
    speedIncrease += 10
else if (using deluxe speed-gro):
    speedIncrease += 25
else if (using hyper speed-gro):
    speedIncrease += 33
if (has agriculturalist profession):
    speedIncrease += 10 
if (paddy bonus):
    speedIncrease += 25
numerator = totalDaysOfCropGrowth * speedIncrease
// Integer division always rounds down.
daysToRemove = totalDaysOfCropGrowth * speedIncrease / 100
if (numerator % 100 != 0):
    // If there is a remainder, round up by incrementing daysToRemove
    daysToRemove += 1
 
Top