Skip to content

Fix OverflowException in Average() for int type by using long accumulator#240

Merged
neuecc merged 2 commits intoCysharp:mainfrom
prozolic:average
Feb 12, 2026
Merged

Fix OverflowException in Average() for int type by using long accumulator#240
neuecc merged 2 commits intoCysharp:mainfrom
prozolic:average

Conversation

@prozolic
Copy link
Copy Markdown
Contributor

@prozolic prozolic commented Feb 1, 2026

Summary

In the following, when executing Average() with large values in enumeration patterns, System.Linq does not throw an exception, but ZLinq throws an OverflowException. Therefore, I fixed the code so that for int type only, the sum calculation is performed using double, matching System.Linq's behavior.

Reproduction Steps

var largeValues = new[] { int.MaxValue / 2, int.MaxValue / 2, int.MaxValue / 2 };
var expected = ToEnumerable(largeValues).Average();
var actual = ToEnumerable(largeValues).AsValueEnumerable().Average();

static IEnumerable<T> ToEnumerable<T>(IEnumerable<T> source)
{
    foreach (var item in source)
    {
        yield return item;
    }
}

Expected behavior

Calculated without throwing an error.

Actual behavior

OverflowException is thrown.

Statck trace

System.OverflowException: Arithmetic operation resulted in an overflow.
   at System.Int32.System.Numerics.IAdditionOperators<System.Int32,System.Int32,System.Int32>.op_CheckedAddition(Int32 left, Int32 right)
   at ZLinq.ValueEnumerableExtensions.Average[TEnumerator,TSource](ValueEnumerable`2 source)
   at Program.<Main>$(String[] args)

Copilot AI review requested due to automatic review settings February 1, 2026 01:52
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes an OverflowException that occurs when calculating Average() for int types with large values in ZLinq, bringing behavior in line with System.Linq. The fix uses a long accumulator instead of int to prevent overflow when summing large integer values.

Changes:

  • Modified Average() implementations to accumulate int values using long instead of int
  • Added tests to verify overflow protection for both nullable and non-nullable int sequences
  • Applied fix across all code paths: NET8_0_OR_GREATER and pre-NET8, for both span-based and enumerator-based implementations

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
tests/ZLinq.Tests/Linq/AverageTest.cs Added OverflowProtection test with 3 large int values and Nullable_OverflowProtection test with nullable ints to verify the fix
src/ZLinq/Linq/Average.cs Updated all int-specific Average() implementations (both nullable and non-nullable, across NET8 and pre-NET8 paths) to use long accumulator instead of int

@neuecc
Copy link
Copy Markdown
Member

neuecc commented Feb 12, 2026

Thank you!
I think that's a good solution!

@neuecc neuecc merged commit a5d3031 into Cysharp:main Feb 12, 2026
4 checks passed
@prozolic prozolic deleted the average branch February 12, 2026 12:40
IhateTrains pushed a commit to ParadoxGameConverters/ImperatorToCK3 that referenced this pull request Feb 13, 2026
Updated [ZLinq](https://github.com/Cysharp/ZLinq) from 1.5.4 to 1.5.5.

<details>
<summary>Release notes</summary>

_Sourced from [ZLinq's
releases](https://github.com/Cysharp/ZLinq/releases)._

## 1.5.5

## What's Changed
* Update GH action benchmark results link by @​SnakyBeaky in
Cysharp/ZLinq#238
* chore(deps): bump actions/upload-artifact from 5.0.0 to 6.0.0 by
@​dependabot[bot] in Cysharp/ZLinq#239
* Fix OverflowException in Average() for int type by using long
accumulator by @​prozolic in Cysharp/ZLinq#240
* Fix double dispose in OrderBy, Shuffle, Shuffle.SkipTake by @​apkd in
Cysharp/ZLinq#241

## New Contributors
* @​SnakyBeaky made their first contribution in
Cysharp/ZLinq#238

**Full Changelog**:
Cysharp/ZLinq@1.5.4...1.5.5

Commits viewable in [compare
view](Cysharp/ZLinq@1.5.4...1.5.5).
</details>

[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=ZLinq&package-manager=nuget&previous-version=1.5.4&new-version=1.5.5)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants