You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
If you are able to, could you please create a pull request with a unit test that highlights the two errors and what the results should be? Huge bonus points if you also provide a fix for the implementation.
It will help move this along much faster, I have limited time to look into it.
I think the core issue here is that Level + Level and Level - Level currently encode one specific interpretation of dB arithmetic, but users can reasonably expect another.
Today, logarithmic quantities implement +/- as linear-space aggregation:
Leveltotal=level1+level2;
This means roughly:
10*log10(10^(level1/10)+10^(level2/10))
So this does not produce direct value arithmetic:
1.6 dB +0.7 dB !=2.3 dB
That behavior is useful when adding quantities represented in dB, but it is surprising when the user wants to add/subtract dB values as gains/ratios.
For v6, I think we should make this explicit and avoid +/- for logarithmic quantities. My current preference is to provide named APIs for the two meanings:
// Convert to linear space, operate, convert back.Leveltotal=level1.LinearAdd(level2);Leveltotal=levels.LinearSum();Levelmean=levels.LinearMean();// Operate directly on the logarithmic values.Levelgain=level1.LogValueAdd(level2);Leveldelta=level1.LogValueSubtract(level2);Levelgain=Level.FromDecibels(level1.Decibels+level2.Decibels);
The exact names can be discussed, but I think the important part is this split:
Linear* means convert to linear space, do the operation, convert back.
LogValue* means operate directly on the logarithmic unit values.
+/- should probably be removed for logarithmic quantities, because both interpretations are common enough that the operators are ambiguous.
I think, you implemented sound level measurement in dB and this is ok. My use of dB is a ratio of 2 quantities and this is also a very common application. Several ratios(attenuation, amplification, ...) expressed in logarithmic can be added or subtracted instead of multipication.
So I think you should add dB as unit to Ratio. Adding a ratio to a quantity multiplies the quantity with the ratio. Multiplication of a quantity with a ratio should have the same result.
dB is one of several ambiguous units abbreviations.
Your proposed work around is not applicable for me. I use UnitsNet within C#-scripting and the expressions are written by the users of our Software.
I would prefere a logarithmic ratio instead of changing dB for sound level measurement.
I reproduced this with your code verbatim against master (assembly 6.0.0.0), and I do not
think it is a bug — but the reasoning is worth writing down, and it did turn up something
adjacent that was untested.
Level is a logarithmic quantity, so + combines two levels in linear power space rather
than adding their decibel numbers:
UnitsNet returns
10·log10(10^(L1/10) ± 10^(L2/10))
L1 ± L2
level1 + level2
4.18357203248652 dB
4.183572032487 ✓
2.3 ✗
level1 - level2
-5.67764957318026 dB
-5.67764957318 ✓
0.9 ✗
So the results match the logarithmic definition exactly, to the last digit UnitsNet prints.
Your expectation — "dB additions or subtractions should be executed without any
transformations" — is the correct operation for a gain, which is a dimensionless ratio,
not a level. Combining two levels and applying a gain to a level are different operations, and
the calculator you linked has separate entries for them. The arithmetic one already works today:
Level.FromDecibels(level1.Decibels+level2.Decibels)// 2.3 dB
Level.FromDecibels(level1.Decibels-level2.Decibels)// 0.9 dB
If your signals are genuinely levels relative to the same reference, 4.18 dB is the right
answer for their sum.
@angularsen — you asked for a test showing the errors and the expected results. Since the
arithmetic turns out to be correct there is no failing test to write, but reproducing this did
surface two silent returns that nothing covered:
Level.FromDecibels(40) - Level.FromDecibels(40) -> -Infinity dB
Level.FromDecibels(0.7) - Level.FromDecibels(1.6) -> NaN dB
The second is inconsistent with the constructor, which rejects a non-positive ratio with ArgumentOutOfRangeException and the message "The base-10 logarithm of a number ≤ 0 is
undefined", while operator- performs that same logarithm and returns NaN silently.
#1725 pins all three cases as characterisation tests. It changes no behaviour — making operator- throw would be a breaking change and your call, so I have deliberately left it out
and can open that separately if you want it.
You had also said to re-evaluate after #1587; that merged on 2025-08-03, and the above is
measured after it.
I owe both of you a correction: I wrote that comment without reading this thread properly, and
it shows. @angularsen had already set out the linear-space-vs-dB-value split on 31 July, in more
detail than I did, and had already named Level.FromDecibels(a.Decibels + b.Decibels) — which I
then offered back as if it were an answer. @BernhardJosef had already explained on 3 August why
that shape does not work for him. Restating the first and ignoring the second was not useful.
Reading it properly, the disagreement is narrower than "is this a bug", and there is one thing I
can add that is measured rather than argued.
Every dB-carrying quantity in UnitsNet composes in linear space. None composes as a gain.
Measured on master, assembly 6.0.0.0:
type
1.6 + 0.7
dB-value addition would give
Level (dB)
4.18357203248652
2.3
PowerRatio (dBW)
4.18357203248652
2.3
AmplitudeRatio (dBV)
7.1822515393836
2.3
Ratio
no dB unit exists
—
AmplitudeRatio and PowerRatio are named "ratio" but are referenced to a volt and a watt, so
they are levels too. Ratio is dimensionless but is not logarithmic and has no dB unit. So @BernhardJosef's case — a dimensionless logarithmic gain, where composing two gains multiplies
the linear ratios and therefore adds the decibels — currently has no type at all. That is why no
workaround built out of the existing types fits it.
Which raises a question about the v6 plan rather than an objection to it. The proposal removes +/- because both interpretations are common enough to be ambiguous. But the ambiguity looks
like it comes from a missing type rather than from the operators: within a level, + can only
sensibly mean linear-space combination; within a dimensionless dB gain, + can only sensibly
mean dB addition. If both types existed, the operand types would disambiguate and + would be
unambiguous in each.
That matters specifically for @BernhardJosef's constraint, which named methods cannot meet:
end users write the expressions in C# script, so whatever is correct has to be spelled a + b.
I am not proposing this over your plan — you know the compatibility surface and I have landed
nothing here yet. I am asking whether a separate logarithmic-ratio type was already considered
and rejected, because if it was, the reasoning would be worth having in the thread.
On #1725: it pins the current - edge cases, and I should flag that two of them are unaffected
by the v6 direction while one is not. v - v giving -Infinity and smaller - larger giving NaN silently will need an answer under any spelling, including LinearSubtract; the
constructor already rejects the same non-positive logarithm with ArgumentOutOfRangeException.
The addition test in that PR does pin operator behaviour you intend to remove, so treat it as a
record of today rather than as something to preserve — happy to drop it if you would rather not
have it in the suite.
Activity
angularsen commentedon Jul 26, 2025
Hi, thanks for reporting.
If you are able to, could you please create a pull request with a unit test that highlights the two errors and what the results should be? Huge bonus points if you also provide a fix for the implementation.
It will help move this along much faster, I have limited time to look into it.
angularsen commentedon Jul 27, 2025
Relevant changes coming in #1587
Let's re-evaluate after those are merged.
github-actions commentedon Aug 27, 2025
This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 7 days.
github-actions commentedon Sep 4, 2025
This issue was automatically closed due to inactivity.
angularsen commentedon Jul 31, 2026
I think the core issue here is that
Level + LevelandLevel - Levelcurrently encode one specific interpretation of dB arithmetic, but users can reasonably expect another.Today, logarithmic quantities implement
+/-as linear-space aggregation:This means roughly:
So this does not produce direct value arithmetic:
That behavior is useful when adding quantities represented in dB, but it is surprising when the user wants to add/subtract dB values as gains/ratios.
For v6, I think we should make this explicit and avoid
+/-for logarithmic quantities. My current preference is to provide named APIs for the two meanings:The exact names can be discussed, but I think the important part is this split:
Linear*means convert to linear space, do the operation, convert back.LogValue*means operate directly on the logarithmic unit values.+/-should probably be removed for logarithmic quantities, because both interpretations are common enough that the operators are ambiguous.How does this match your expectation?
BernhardJosef commentedon Aug 3, 2026
I think, you implemented sound level measurement in dB and this is ok. My use of dB is a ratio of 2 quantities and this is also a very common application. Several ratios(attenuation, amplification, ...) expressed in logarithmic can be added or subtracted instead of multipication.
So I think you should add dB as unit to Ratio. Adding a ratio to a quantity multiplies the quantity with the ratio. Multiplication of a quantity with a ratio should have the same result.
dB is one of several ambiguous units abbreviations.
Your proposed work around is not applicable for me. I use UnitsNet within C#-scripting and the expressions are written by the users of our Software.
I would prefere a logarithmic ratio instead of changing dB for sound level measurement.
I can support you with the test of ratio unit dB
Rafael-SOWNet commentedon Aug 6, 2026
I reproduced this with your code verbatim against
master(assembly 6.0.0.0), and I do notthink it is a bug — but the reasoning is worth writing down, and it did turn up something
adjacent that was untested.
Levelis a logarithmic quantity, so+combines two levels in linear power space ratherthan adding their decibel numbers:
10·log10(10^(L1/10) ± 10^(L2/10))L1 ± L2level1 + level24.18357203248652 dBlevel1 - level2-5.67764957318026 dBSo the results match the logarithmic definition exactly, to the last digit UnitsNet prints.
Your expectation — "dB additions or subtractions should be executed without any
transformations" — is the correct operation for a gain, which is a dimensionless ratio,
not a level. Combining two levels and applying a gain to a level are different operations, and
the calculator you linked has separate entries for them. The arithmetic one already works today:
If your signals are genuinely levels relative to the same reference,
4.18 dBis the rightanswer for their sum.
@angularsen — you asked for a test showing the errors and the expected results. Since the
arithmetic turns out to be correct there is no failing test to write, but reproducing this did
surface two silent returns that nothing covered:
The second is inconsistent with the constructor, which rejects a non-positive ratio with
ArgumentOutOfRangeExceptionand the message "The base-10 logarithm of a number ≤ 0 isundefined", while
operator-performs that same logarithm and returnsNaNsilently.#1725 pins all three cases as characterisation tests. It changes no behaviour — making
operator-throw would be a breaking change and your call, so I have deliberately left it outand can open that separately if you want it.
You had also said to re-evaluate after #1587; that merged on 2025-08-03, and the above is
measured after it.
Rafael-SOWNet commentedon Aug 7, 2026
I owe both of you a correction: I wrote that comment without reading this thread properly, and
it shows. @angularsen had already set out the linear-space-vs-dB-value split on 31 July, in more
detail than I did, and had already named
Level.FromDecibels(a.Decibels + b.Decibels)— which Ithen offered back as if it were an answer. @BernhardJosef had already explained on 3 August why
that shape does not work for him. Restating the first and ignoring the second was not useful.
Reading it properly, the disagreement is narrower than "is this a bug", and there is one thing I
can add that is measured rather than argued.
Every dB-carrying quantity in UnitsNet composes in linear space. None composes as a gain.
Measured on
master, assembly 6.0.0.0:1.6 + 0.7Level(dB)4.18357203248652PowerRatio(dBW)4.18357203248652AmplitudeRatio(dBV)7.1822515393836RatioAmplitudeRatioandPowerRatioare named "ratio" but are referenced to a volt and a watt, sothey are levels too.
Ratiois dimensionless but is not logarithmic and has no dB unit. So@BernhardJosef's case — a dimensionless logarithmic gain, where composing two gains multiplies
the linear ratios and therefore adds the decibels — currently has no type at all. That is why no
workaround built out of the existing types fits it.
Which raises a question about the v6 plan rather than an objection to it. The proposal removes
+/-because both interpretations are common enough to be ambiguous. But the ambiguity lookslike it comes from a missing type rather than from the operators: within a level,
+can onlysensibly mean linear-space combination; within a dimensionless dB gain,
+can only sensiblymean dB addition. If both types existed, the operand types would disambiguate and
+would beunambiguous in each.
That matters specifically for @BernhardJosef's constraint, which named methods cannot meet:
end users write the expressions in C# script, so whatever is correct has to be spelled
a + b.I am not proposing this over your plan — you know the compatibility surface and I have landed
nothing here yet. I am asking whether a separate logarithmic-ratio type was already considered
and rejected, because if it was, the reasoning would be worth having in the thread.
On #1725: it pins the current
-edge cases, and I should flag that two of them are unaffectedby the v6 direction while one is not.
v - vgiving-Infinityandsmaller - largergivingNaNsilently will need an answer under any spelling, includingLinearSubtract; theconstructor already rejects the same non-positive logarithm with
ArgumentOutOfRangeException.The addition test in that PR does pin operator behaviour you intend to remove, so treat it as a
record of today rather than as something to preserve — happy to drop it if you would rather not
have it in the suite.