Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,13 @@ arithmetic, so a `decimal` length has 28 significant digits. A value a `double`
`BigInteger` of 2^2048, is scaled by powers of four into [1, 4) for the seed, and the root is scaled
back by the matching power of two. A root that does not settle throws `ArithmeticException` rather
than returning an estimate. The logarithmic scales and the hand-written audio types still compute
through `double`.
through `double`, and as of #235 every generated conversion says so in its own XML `<remarks>`
rather than only here — the method tooltip is where a `decimal` or `PreciseNumber` consumer spends
the precision, so that is where the cost is stated. `SourceGeneratorTests` counts the remarks
against the conversions that actually drop to `double`, so a conversion added later cannot ship
undocumented. If the scales ever compute in `T`'s own arithmetic (option 3 on #235, which wants
`Exp`/`Log` on `PreciseNumber` first — ktsu-dev/PreciseNumber#81), the remarks become false and
should be removed with the `double` path rather than left to rot.

`StorageMath` is public API, not just the generator's helper (#239): an application doing its own
vector math over quantities would otherwise reimplement the root, and worse. `Cbrt`, `RootN` and
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,14 @@ namespace ktsu.Semantics.Quantities;
/// An octave is 1200 cents: cents = 1200·log2(frequencyRatio).
/// Logarithmic scales don't obey linear arithmetic, so this type is generated as a
/// standalone companion (from logarithmic.json) rather than a physical dimension.
/// <para>
/// <b>Precision:</b> the conversions to and from the linear counterparts compute in
/// <see langword="double"/> whatever <typeparamref name="T"/> is, so a value carried in a
/// storage type wider than <see langword="double"/> — <see langword="decimal"/>, or
/// <c>PreciseNumber</c> — is accurate to about fifteen significant digits once it has been
/// through one. Arithmetic, comparison and the raw factory keep every digit
/// <typeparamref name="T"/> holds; only the logarithm and its inverse do not.
/// </para>
/// </remarks>
/// <typeparam name="T">The floating-point storage type.</typeparam>
/// <param name="Value">The scale value.</param>
Expand All @@ -34,6 +42,13 @@ public readonly partial record struct Cents<T>(T Value) : IComparable<Cents<T>>
/// </summary>
/// <param name="linear">The linear <see cref="Ratio{T}"/>.</param>
/// <returns>A new <see cref="Cents{T}"/>. A linear value of zero maps to negative infinity.</returns>
/// <remarks>
/// Computes in <see langword="double"/> whatever <typeparamref name="T"/> is: the value is
/// converted to <see langword="double"/>, the logarithm or power is taken there, and the
/// result is converted back. A storage type wider than <see langword="double"/> —
/// <see langword="decimal"/>, or <c>PreciseNumber</c> — therefore keeps about fifteen
/// significant digits across this conversion, rather than the precision it is capable of.
/// </remarks>
public static Cents<T> FromFrequencyRatio(Ratio<T> linear)
{
double linearValue = double.CreateChecked(linear.Value);
Expand All @@ -44,6 +59,13 @@ public static Cents<T> FromFrequencyRatio(Ratio<T> linear)
/// Converts this interval to a frequency ratio using ratio = 2^(cents/1200).
/// </summary>
/// <returns>The linear <see cref="Ratio{T}"/>.</returns>
/// <remarks>
/// Computes in <see langword="double"/> whatever <typeparamref name="T"/> is: the value is
/// converted to <see langword="double"/>, the logarithm or power is taken there, and the
/// result is converted back. A storage type wider than <see langword="double"/> —
/// <see langword="decimal"/>, or <c>PreciseNumber</c> — therefore keeps about fifteen
/// significant digits across this conversion, rather than the precision it is capable of.
/// </remarks>
public Ratio<T> ToFrequencyRatio()
{
double scaleValue = double.CreateChecked(Value);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,14 @@ namespace ktsu.Semantics.Quantities;
/// Decibels express ratios on a logarithmic scale. Amplitude/field quantities use dB = 20·log10(ratio); power quantities use dB = 10·log10(ratio). A level of 0 dB is unity.
/// Logarithmic scales don't obey linear arithmetic, so this type is generated as a
/// standalone companion (from logarithmic.json) rather than a physical dimension.
/// <para>
/// <b>Precision:</b> the conversions to and from the linear counterparts compute in
/// <see langword="double"/> whatever <typeparamref name="T"/> is, so a value carried in a
/// storage type wider than <see langword="double"/> — <see langword="decimal"/>, or
/// <c>PreciseNumber</c> — is accurate to about fifteen significant digits once it has been
/// through one. Arithmetic, comparison and the raw factory keep every digit
/// <typeparamref name="T"/> holds; only the logarithm and its inverse do not.
/// </para>
/// </remarks>
/// <typeparam name="T">The floating-point storage type.</typeparam>
/// <param name="Value">The scale value.</param>
Expand All @@ -34,6 +42,13 @@ public readonly partial record struct Decibels<T>(T Value) : IComparable<Decibel
/// </summary>
/// <param name="linear">The linear <see cref="Gain{T}"/>.</param>
/// <returns>A new <see cref="Decibels{T}"/>. A linear value of zero maps to negative infinity.</returns>
/// <remarks>
/// Computes in <see langword="double"/> whatever <typeparamref name="T"/> is: the value is
/// converted to <see langword="double"/>, the logarithm or power is taken there, and the
/// result is converted back. A storage type wider than <see langword="double"/> —
/// <see langword="decimal"/>, or <c>PreciseNumber</c> — therefore keeps about fifteen
/// significant digits across this conversion, rather than the precision it is capable of.
/// </remarks>
public static Decibels<T> FromGain(Gain<T> linear)
{
double linearValue = double.CreateChecked(linear.Value);
Expand All @@ -44,6 +59,13 @@ public static Decibels<T> FromGain(Gain<T> linear)
/// Converts this level to a linear amplitude gain using gain = 10^(dB/20).
/// </summary>
/// <returns>The linear <see cref="Gain{T}"/>.</returns>
/// <remarks>
/// Computes in <see langword="double"/> whatever <typeparamref name="T"/> is: the value is
/// converted to <see langword="double"/>, the logarithm or power is taken there, and the
/// result is converted back. A storage type wider than <see langword="double"/> —
/// <see langword="decimal"/>, or <c>PreciseNumber</c> — therefore keeps about fifteen
/// significant digits across this conversion, rather than the precision it is capable of.
/// </remarks>
public Gain<T> ToAmplitude()
{
double scaleValue = double.CreateChecked(Value);
Expand All @@ -55,6 +77,13 @@ public Gain<T> ToAmplitude()
/// </summary>
/// <param name="linear">The linear <see cref="Ratio{T}"/>.</param>
/// <returns>A new <see cref="Decibels{T}"/>. A linear value of zero maps to negative infinity.</returns>
/// <remarks>
/// Computes in <see langword="double"/> whatever <typeparamref name="T"/> is: the value is
/// converted to <see langword="double"/>, the logarithm or power is taken there, and the
/// result is converted back. A storage type wider than <see langword="double"/> —
/// <see langword="decimal"/>, or <c>PreciseNumber</c> — therefore keeps about fifteen
/// significant digits across this conversion, rather than the precision it is capable of.
/// </remarks>
public static Decibels<T> FromPowerRatio(Ratio<T> linear)
{
double linearValue = double.CreateChecked(linear.Value);
Expand All @@ -65,6 +94,13 @@ public static Decibels<T> FromPowerRatio(Ratio<T> linear)
/// Converts this level to a linear power ratio using ratio = 10^(dB/10).
/// </summary>
/// <returns>The linear <see cref="Ratio{T}"/>.</returns>
/// <remarks>
/// Computes in <see langword="double"/> whatever <typeparamref name="T"/> is: the value is
/// converted to <see langword="double"/>, the logarithm or power is taken there, and the
/// result is converted back. A storage type wider than <see langword="double"/> —
/// <see langword="decimal"/>, or <c>PreciseNumber</c> — therefore keeps about fifteen
/// significant digits across this conversion, rather than the precision it is capable of.
/// </remarks>
public Ratio<T> ToPower()
{
double scaleValue = double.CreateChecked(Value);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,14 @@ namespace ktsu.Semantics.Quantities;
/// DI = 10·log10(I_axis / I_average).
/// Logarithmic scales don't obey linear arithmetic, so this type is generated as a
/// standalone companion (from logarithmic.json) rather than a physical dimension.
/// <para>
/// <b>Precision:</b> the conversions to and from the linear counterparts compute in
/// <see langword="double"/> whatever <typeparamref name="T"/> is, so a value carried in a
/// storage type wider than <see langword="double"/> — <see langword="decimal"/>, or
/// <c>PreciseNumber</c> — is accurate to about fifteen significant digits once it has been
/// through one. Arithmetic, comparison and the raw factory keep every digit
/// <typeparamref name="T"/> holds; only the logarithm and its inverse do not.
/// </para>
/// </remarks>
/// <typeparam name="T">The floating-point storage type.</typeparam>
/// <param name="Value">The scale value.</param>
Expand All @@ -34,6 +42,13 @@ public readonly partial record struct DirectionalityIndex<T>(T Value) : ICompara
/// </summary>
/// <param name="linear">The linear <see cref="Ratio{T}"/>.</param>
/// <returns>A new <see cref="DirectionalityIndex{T}"/>. A linear value of zero maps to negative infinity.</returns>
/// <remarks>
/// Computes in <see langword="double"/> whatever <typeparamref name="T"/> is: the value is
/// converted to <see langword="double"/>, the logarithm or power is taken there, and the
/// result is converted back. A storage type wider than <see langword="double"/> —
/// <see langword="decimal"/>, or <c>PreciseNumber</c> — therefore keeps about fifteen
/// significant digits across this conversion, rather than the precision it is capable of.
/// </remarks>
public static DirectionalityIndex<T> FromIntensityRatio(Ratio<T> linear)
{
double linearValue = double.CreateChecked(linear.Value);
Expand All @@ -44,6 +59,13 @@ public static DirectionalityIndex<T> FromIntensityRatio(Ratio<T> linear)
/// Converts this index to the linear intensity ratio using ratio = 10^(DI/10).
/// </summary>
/// <returns>The linear <see cref="Ratio{T}"/>.</returns>
/// <remarks>
/// Computes in <see langword="double"/> whatever <typeparamref name="T"/> is: the value is
/// converted to <see langword="double"/>, the logarithm or power is taken there, and the
/// result is converted back. A storage type wider than <see langword="double"/> —
/// <see langword="decimal"/>, or <c>PreciseNumber</c> — therefore keeps about fifteen
/// significant digits across this conversion, rather than the precision it is capable of.
/// </remarks>
public Ratio<T> ToIntensityRatio()
{
double scaleValue = double.CreateChecked(Value);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,14 @@ namespace ktsu.Semantics.Quantities;
/// pH is a logarithmic scale over the linear Concentration quantity (stored in the SI base mol/m³; 1 mol/L = 1000 mol/m³).
/// Logarithmic scales don't obey linear arithmetic, so this type is generated as a
/// standalone companion (from logarithmic.json) rather than a physical dimension.
/// <para>
/// <b>Precision:</b> the conversions to and from the linear counterparts compute in
/// <see langword="double"/> whatever <typeparamref name="T"/> is, so a value carried in a
/// storage type wider than <see langword="double"/> — <see langword="decimal"/>, or
/// <c>PreciseNumber</c> — is accurate to about fifteen significant digits once it has been
/// through one. Arithmetic, comparison and the raw factory keep every digit
/// <typeparamref name="T"/> holds; only the logarithm and its inverse do not.
/// </para>
/// </remarks>
/// <typeparam name="T">The floating-point storage type.</typeparam>
/// <param name="Value">The scale value.</param>
Expand All @@ -34,6 +42,13 @@ public readonly partial record struct PH<T>(T Value) : IComparable<PH<T>>
/// </summary>
/// <param name="linear">The linear <see cref="Concentration{T}"/>.</param>
/// <returns>A new <see cref="PH{T}"/>. A linear value of zero maps to negative infinity.</returns>
/// <remarks>
/// Computes in <see langword="double"/> whatever <typeparamref name="T"/> is: the value is
/// converted to <see langword="double"/>, the logarithm or power is taken there, and the
/// result is converted back. A storage type wider than <see langword="double"/> —
/// <see langword="decimal"/>, or <c>PreciseNumber</c> — therefore keeps about fifteen
/// significant digits across this conversion, rather than the precision it is capable of.
/// </remarks>
public static PH<T> FromHydrogenConcentration(Concentration<T> linear)
{
double linearValue = double.CreateChecked(linear.Value);
Expand All @@ -45,6 +60,13 @@ public static PH<T> FromHydrogenConcentration(Concentration<T> linear)
/// Converts this pH to the equivalent hydrogen-ion concentration using [H⁺] = 10^(−pH) mol/L.
/// </summary>
/// <returns>The linear <see cref="Concentration{T}"/>.</returns>
/// <remarks>
/// Computes in <see langword="double"/> whatever <typeparamref name="T"/> is: the value is
/// converted to <see langword="double"/>, the logarithm or power is taken there, and the
/// result is converted back. A storage type wider than <see langword="double"/> —
/// <see langword="decimal"/>, or <c>PreciseNumber</c> — therefore keeps about fifteen
/// significant digits across this conversion, rather than the precision it is capable of.
/// </remarks>
public Concentration<T> ToHydrogenConcentration()
{
double scaleValue = double.CreateChecked(Value);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,14 @@ namespace ktsu.Semantics.Quantities;
/// An octave is 12 semitones: semitones = 12·log2(frequencyRatio).
/// Logarithmic scales don't obey linear arithmetic, so this type is generated as a
/// standalone companion (from logarithmic.json) rather than a physical dimension.
/// <para>
/// <b>Precision:</b> the conversions to and from the linear counterparts compute in
/// <see langword="double"/> whatever <typeparamref name="T"/> is, so a value carried in a
/// storage type wider than <see langword="double"/> — <see langword="decimal"/>, or
/// <c>PreciseNumber</c> — is accurate to about fifteen significant digits once it has been
/// through one. Arithmetic, comparison and the raw factory keep every digit
/// <typeparamref name="T"/> holds; only the logarithm and its inverse do not.
/// </para>
/// </remarks>
/// <typeparam name="T">The floating-point storage type.</typeparam>
/// <param name="Value">The scale value.</param>
Expand All @@ -34,6 +42,13 @@ public readonly partial record struct Semitones<T>(T Value) : IComparable<Semito
/// </summary>
/// <param name="linear">The linear <see cref="Ratio{T}"/>.</param>
/// <returns>A new <see cref="Semitones{T}"/>. A linear value of zero maps to negative infinity.</returns>
/// <remarks>
/// Computes in <see langword="double"/> whatever <typeparamref name="T"/> is: the value is
/// converted to <see langword="double"/>, the logarithm or power is taken there, and the
/// result is converted back. A storage type wider than <see langword="double"/> —
/// <see langword="decimal"/>, or <c>PreciseNumber</c> — therefore keeps about fifteen
/// significant digits across this conversion, rather than the precision it is capable of.
/// </remarks>
public static Semitones<T> FromFrequencyRatio(Ratio<T> linear)
{
double linearValue = double.CreateChecked(linear.Value);
Expand All @@ -44,6 +59,13 @@ public static Semitones<T> FromFrequencyRatio(Ratio<T> linear)
/// Converts this interval to a frequency ratio using ratio = 2^(semitones/12).
/// </summary>
/// <returns>The linear <see cref="Ratio{T}"/>.</returns>
/// <remarks>
/// Computes in <see langword="double"/> whatever <typeparamref name="T"/> is: the value is
/// converted to <see langword="double"/>, the logarithm or power is taken there, and the
/// result is converted back. A storage type wider than <see langword="double"/> —
/// <see langword="decimal"/>, or <c>PreciseNumber</c> — therefore keeps about fifteen
/// significant digits across this conversion, rather than the precision it is capable of.
/// </remarks>
public Ratio<T> ToFrequencyRatio()
{
double scaleValue = double.CreateChecked(Value);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,14 @@ namespace ktsu.Semantics.Quantities;
/// SIL is a logarithmic power quantity: SIL = 10·log10(I / I₀) with I₀ = 10⁻¹² W/m².
/// Logarithmic scales don't obey linear arithmetic, so this type is generated as a
/// standalone companion (from logarithmic.json) rather than a physical dimension.
/// <para>
/// <b>Precision:</b> the conversions to and from the linear counterparts compute in
/// <see langword="double"/> whatever <typeparamref name="T"/> is, so a value carried in a
/// storage type wider than <see langword="double"/> — <see langword="decimal"/>, or
/// <c>PreciseNumber</c> — is accurate to about fifteen significant digits once it has been
/// through one. Arithmetic, comparison and the raw factory keep every digit
/// <typeparamref name="T"/> holds; only the logarithm and its inverse do not.
/// </para>
/// </remarks>
/// <typeparam name="T">The floating-point storage type.</typeparam>
/// <param name="Value">The scale value.</param>
Expand All @@ -34,6 +42,13 @@ public readonly partial record struct SoundIntensityLevel<T>(T Value) : ICompara
/// </summary>
/// <param name="linear">The linear <see cref="SoundIntensity{T}"/>.</param>
/// <returns>A new <see cref="SoundIntensityLevel{T}"/>. A linear value of zero maps to negative infinity.</returns>
/// <remarks>
/// Computes in <see langword="double"/> whatever <typeparamref name="T"/> is: the value is
/// converted to <see langword="double"/>, the logarithm or power is taken there, and the
/// result is converted back. A storage type wider than <see langword="double"/> —
/// <see langword="decimal"/>, or <c>PreciseNumber</c> — therefore keeps about fifteen
/// significant digits across this conversion, rather than the precision it is capable of.
/// </remarks>
public static SoundIntensityLevel<T> FromSoundIntensity(SoundIntensity<T> linear)
{
double linearValue = double.CreateChecked(linear.Value);
Expand All @@ -45,6 +60,13 @@ public static SoundIntensityLevel<T> FromSoundIntensity(SoundIntensity<T> linear
/// Converts this level to the equivalent linear sound intensity using I = I₀·10^(SIL/10).
/// </summary>
/// <returns>The linear <see cref="SoundIntensity{T}"/>.</returns>
/// <remarks>
/// Computes in <see langword="double"/> whatever <typeparamref name="T"/> is: the value is
/// converted to <see langword="double"/>, the logarithm or power is taken there, and the
/// result is converted back. A storage type wider than <see langword="double"/> —
/// <see langword="decimal"/>, or <c>PreciseNumber</c> — therefore keeps about fifteen
/// significant digits across this conversion, rather than the precision it is capable of.
/// </remarks>
public SoundIntensity<T> ToSoundIntensity()
{
double scaleValue = double.CreateChecked(Value);
Expand Down
Loading
Loading