Home > Enterprise >  C# percentage calculation suddenly goes negative
C# percentage calculation suddenly goes negative

Time:09-27

I have a program that downloads some lecture videos to view offline. I use below code to download and calculate percentage. Around 32-33% the calculated percentage is always going negative but in a weird way (33 -> -33 -> -32 -> -31 -> -30 etc...) till it hits 33 again. Download is finished then. I even calculated manually. Debug output is also below the code.

This happens consistently so i am doing something wrong surely but where?

private async Task CopyStream(
      Lecture lecture,
      Stream source,
      Stream destination,
      int sourceLength,
      CancellationToken token,
      int bufferSize = (16 * 1024))
    {
      var buffer = new byte[bufferSize];

      if (sourceLength <= 0) return;

      var totalBytesCopied = 0;
      var bytesRead = -1;

      while (bytesRead != 0)
      {
        bytesRead = await source.ReadAsync(buffer, 0, buffer.Length, token);

        if (bytesRead == 0) break;

        await destination.WriteAsync(buffer, 0, buffer.Length, token);

        totalBytesCopied  = bytesRead;

        var progress = (int)Math.Round((double)(100 * totalBytesCopied) / sourceLength);

        Debug.WriteLine(
          $"Lecture={lecture.Title}, "  
          $"sourceLength={sourceLength}, "  
          $"totalBytesCopied={totalBytesCopied}, "  
          $"bytesRead={bytesRead}, progress={progress}");

        RaiseLectureDownloadProgressChangedEvent(null,
            new LectureDownloadProgressChangedEventArgs(lecture, progress));
      }
    }
Lecture=Lecture1, sourceLength=65777753, totalBytesCopied=21404088, bytesRead=16384, progress=33
Lecture=Lecture1, sourceLength=65777753, totalBytesCopied=21420472, bytesRead=16384, progress=33
Lecture=Lecture1, sourceLength=65777753, totalBytesCopied=21436856, bytesRead=16384, progress=33
Lecture=Lecture1, sourceLength=65777753, totalBytesCopied=21453240, bytesRead=16384, progress=33
Lecture=Lecture1, sourceLength=65777753, totalBytesCopied=21469624, bytesRead=16384, progress=33
Lecture=Lecture1, sourceLength=65777753, totalBytesCopied=21486008, bytesRead=16384, progress=-33
Lecture=Lecture1, sourceLength=65777753, totalBytesCopied=21502392, bytesRead=16384, progress=-33
Lecture=Lecture1, sourceLength=65777753, totalBytesCopied=21518776, bytesRead=16384, progress=-33
Lecture=Lecture1, sourceLength=65777753, totalBytesCopied=21535160, bytesRead=16384, progress=-33
Lecture=Lecture1, sourceLength=65777753, totalBytesCopied=21551544, bytesRead=16384, progress=-33
Lecture=Lecture1, sourceLength=65777753, totalBytesCopied=21567928, bytesRead=16384, progress=-33
Lecture=Lecture1, sourceLength=65777753, totalBytesCopied=21584312, bytesRead=16384, progress=-32
Lecture=Lecture1, sourceLength=65777753, totalBytesCopied=21600696, bytesRead=16384, progress=-32

CodePudding user response:

Lasse V. Karlsen gave the correct explanation in the comment.

To fix it, change:

var progress = (int) Math.Round((double) (100 * totalBytesCopied) / sourceLength);

into:

var progress = (int) Math.Round(((double)100) * totalBytesCopied / sourceLength);

or simply:

var progress = (int) Math.Round(100.0 * totalBytesCopied / sourceLength);

As he says, this will force everything to be done as floating point. The integers will automatically (implicitly) be converted to double in that case. I removed a redundant parenthesis (but you can also just keep it).

  • Related