Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change the underlying Value type from Double to Fraction (WIP) #1377

Open
wants to merge 4 commits into
base: release/v6
Choose a base branch
from

Conversation

lipchev
Copy link
Collaborator

@lipchev lipchev commented Mar 6, 2024

As discussed in #1367 (and many times before) - this is an attempt to solve the rounding issues with the Equality/IComparable contracts (the former having been marked as obsolete).

  • re-introduced the QuantityValue with all standard numeric operations (and implicit conversion from double/decimal)
  • updated the CodeGen replacing all occurrences of the double with QuantityValue
  • restored the IEquality contract using the QuantityValue (which is no longer prone to rounding errors)
  • implemented a custom expression analyzer in order to help pre-process (and simplify) the expressions defined in the json definitions
  • ensure that the tests are passing with the existing tolerances
  • allow the use of NaN / Infinity (see Support for NaN and Infinity danm-de/Fractions#26)
  • fix the required [DataContract] / [DataMember] annotations and see about the backwards-compatibility
  • implement lossless versions of the JsonConverters (the AbbreviatedUnitsConverter currently uses the "G36" which should be fine for most cases, but not ideal for values such as "1/3")
  • replace the non-invertible units (relying on irrational functions) with properties (with optional precision): see Pressure.MetersOfElevation and Angle.Tilt
  • see about avoiding the transition from log-space for the conversion operations of the quantities such as the AmplitudeRatio
  • replace all abstract values generated for the tests with QuantityValue (the implicit conversion from double should work for most cases, but we would probably want the full precision of the QuantityValue for some)
  • remove all Tolerances from the tests
  • (optional) introduce a separate package: ("something like") UnitsNet.Light - which is generated based of the "precise/exact" version (without duplicating the custom code/tests)

Breaking changes:

  • IQuantiy.Value changes from double to QuantityValue (breaks the IHaveQuantity)
  • The conversion from QuantityValue to double is now explicit (unless we're talking about the TypeConverter stuff, I think that still works)
  • Might not be possible to maintain compatibility with the old DataContract schema (affects the default DataContract XML / JSON serailizers, for which we cannot have a "Converter/Surrogates" since .NET Core)

- updated the CodeGen (desktop only) replacing all occurrences of the double with Fraction
- restored the IEquality contract
- implemented a custom expression analyzer in order to help pre-process (and simplify) the expressions defined in the json definitions
- added new extension methods for generating the conversion expressions (w.r.t to the evaluated expression- may include custom functions)
- updated a few conversion coefficients that were a little too precise
- refactored the custom code functions (mostly) using the Fractions (should review the log expressions)
@lipchev
Copy link
Collaborator Author

lipchev commented Mar 11, 2024

@angularsen @tmilnthorp @Muximize
Hey guys, don't mean to push, but It would be helpful if we could have a discussion about the changes proposed in this PR. Specifically, if we assume that the Fractions-based implementation proposed here is a working POC (which I believe it is)- then how would we want to define the public constructors/members in the code-base (this decision is what stopping me from moving on to fixing the tests etc).

Here's a quick "showcase" of the proposed features: (sorry, for some reason the format isn't preserved when I try to copy from it)
#1367 (comment)

The breaking changes in what I've offered here (which is the version with the "maximum number of breaking changes") stem from the following observations:

  • There are only explicit constructors from double and decimal to Fraction (You can implicitly cast int, uint, long, ulong or BigInteger to Fraction)
  • You can explicitly cast from Fraction to any supported data type (int, uint, long, ulong, BigInteger, decimal, double). However, be aware that an OverflowException will be thrown, if the target data type's boundary values are exceeded.

And here are 3 options that I see (apply to both constructors and members):

  1. Max pain: what I've done here- every double is purged from the code-base, replaced by the Fraction type: user needs to write var mass = Mass.FromGrams(Fraction.FromDouble(0.1))
  2. Medium pain: we duplicate the constructors (preserving the ones from double) and only change the IQuantity.Value / As(unit) and the Properties to Fraction (at least we're not dealing with any possible overflows): user needs to write: double value = (double)mass.Value
  3. Little pain: we keep the QuantityValue and hide the Fraction inside it (purging all occurrences of the Fraction class from all public constructors/members): the user won't be able to count on Mass.FromGrams(someMass.Grams) == someMass

And obviously there is everything in between. Here's a reminder of some of the items we need to decide on:

  1. The constructors
  2. The static FromXXX builders
  3. The Value
  4. The As(unit)
  5. The conversion properties (e.g. mass.Grams)

I have no problem with either options (not even sure which version I'd vote for, if there was such a vote..).

@angularsen
Copy link
Owner

@lipchev I'll need a bit of time to get to this, will try to in the next couple of days.

On the surface, it seems to me Little pain is the only viable path among those 3 options.

@Muximize
Copy link
Contributor

But if the Little pain option means Mass.FromGrams(someMass.Grams) == someMass won't work, doesn't that defeat the purpose of changing the underlying type?

@lipchev
Copy link
Collaborator Author

lipchev commented Mar 11, 2024

But if the Little pain option means Mass.FromGrams(someMass.Grams) == someMass won't work, doesn't that defeat the purpose of changing the underlying type?

Yeah, sorry I wasn't clear: what I meant to say is that if you convert to a double (I failed to notice that there wouldn't actually be a conversion to double in this scenario) and then try to construct back the value from double, the equality might break (I was trying to express my general fear of having an implicit conversion with double).

@angularsen
Copy link
Owner

I still intend to get to this, but I have a hard time finding the time to dive deep.

I have not yet reviewed and confirmed the benchmarks as much as I'd need to, but my gut tells me that to avoid upsetting a lot of people, we can't introduce significant performance hits or change the syntax in any significant way, unless it's totally worth it.

I was thinking, how about we roll a separate nuget for this? Something like UnitsNet.Xp.Fractional.

It would be a competing alternative to UnitsNet and very explicitly described as experimental to test it out and gather feedback. I feel that messing with the fundamentals of the package has too big of a risk and requires much thought and feedback, and I just really struggle to find the time and energy to be a good steward for this project and move heavier discussions forward.

An experimental package could just YOLO a bit, no reviews needed. I'd be more comfortable making changes later, if such a package gained traction and interest. Not too different from the NanoFramework nugets, and previously the Windows Runtime Components nugets.

The same approach could be done for other ancient ideas too, like moving from struct to class and use inheritance, or go all in on generics to support any number type.

The only downside I see besides the one time effort of setting up the packages and codegen, is that it's not so easy for consumers that have transitive/nested dependencies on UnitsNet to try it out.

What do you think?

@lipchev
Copy link
Collaborator Author

lipchev commented Mar 27, 2024

I fear this would require a ton of code duplication (code-gen, tests, serialization and all custom code related to the affected interfaces) as well as the increased contribution effort of having two tests to implement.
The worst part is that if we roll out v6 with the QuantityValue gone- we'd be forced to split up the core interfaces, no matter which option we choose for the for the Fractions...

I suggest we try to implement this as the "Little pain" variant- keeping up to breaking changes (from v5->v6) to a minimum and roll that out for testing (we could post some more detailed benchmarks here beforehand)..

@lipchev
Copy link
Collaborator Author

lipchev commented Mar 27, 2024

Alternatively, we could make yet another "experimental" branch (e.g. v6-fractions) - but we still have to pick one of the proposed options to implement :)

lipchev added 3 commits April 10, 2024 20:42
…ctors and numeric operators using the Fraction struct (hidden private field)

- replaced all occurrences of the Fraction with the QuantityValue (making it compatible with v5)
- all tests (but for the DataContractSerializers and those regarding NaN/Infinity) are now passing with the original tolerance (almost no changes were required)
commit 528db5e
Author: Andreas Gullberg Larsen <[email protected]>
Date:   Thu Apr 4 19:40:54 2024 +0200

    JsonNet: 6.0.0-pre006

commit 5f28ca3
Author: Andreas Gullberg Larsen <[email protected]>
Date:   Thu Apr 4 19:40:49 2024 +0200

    UnitsNet: 6.0.0-pre006

commit 8f9a1c0
Merge: 3f71f26 0eb58d3
Author: Andreas Gullberg Larsen <[email protected]>
Date:   Thu Apr 4 19:35:03 2024 +0200

    Merge remote-tracking branch 'origin/master' into release/v6

    # Conflicts:
    #	CodeGen/Generators/NanoFrameworkGen/NuspecGenerator.cs
    #	CodeGen/Generators/NanoFrameworkGen/QuantityGenerator.cs
    #	CodeGen/Generators/UnitsNetGen/QuantityGenerator.cs
    #	UnitsNet.NanoFramework/GeneratedCode/AbsorbedDoseOfIonizingRadiation/UnitsNet.NanoFramework.AbsorbedDoseOfIonizingRadiation.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/Acceleration/UnitsNet.NanoFramework.Acceleration.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/AmountOfSubstance/UnitsNet.NanoFramework.AmountOfSubstance.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/AmplitudeRatio/UnitsNet.NanoFramework.AmplitudeRatio.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/Angle/UnitsNet.NanoFramework.Angle.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/ApparentEnergy/UnitsNet.NanoFramework.ApparentEnergy.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/ApparentPower/UnitsNet.NanoFramework.ApparentPower.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/Area/UnitsNet.NanoFramework.Area.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/AreaDensity/UnitsNet.NanoFramework.AreaDensity.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/AreaMomentOfInertia/UnitsNet.NanoFramework.AreaMomentOfInertia.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/BitRate/UnitsNet.NanoFramework.BitRate.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/BrakeSpecificFuelConsumption/UnitsNet.NanoFramework.BrakeSpecificFuelConsumption.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/Capacitance/UnitsNet.NanoFramework.Capacitance.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/CoefficientOfThermalExpansion/UnitsNet.NanoFramework.CoefficientOfThermalExpansion.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/Compressibility/UnitsNet.NanoFramework.Compressibility.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/Density/UnitsNet.NanoFramework.Density.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/Duration/UnitsNet.NanoFramework.Duration.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/DynamicViscosity/UnitsNet.NanoFramework.DynamicViscosity.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/ElectricAdmittance/UnitsNet.NanoFramework.ElectricAdmittance.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/ElectricCharge/UnitsNet.NanoFramework.ElectricCharge.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/ElectricChargeDensity/UnitsNet.NanoFramework.ElectricChargeDensity.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/ElectricConductance/UnitsNet.NanoFramework.ElectricConductance.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/ElectricConductivity/UnitsNet.NanoFramework.ElectricConductivity.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/ElectricCurrent/UnitsNet.NanoFramework.ElectricCurrent.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/ElectricCurrentDensity/UnitsNet.NanoFramework.ElectricCurrentDensity.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/ElectricCurrentGradient/UnitsNet.NanoFramework.ElectricCurrentGradient.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/ElectricField/UnitsNet.NanoFramework.ElectricField.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/ElectricInductance/UnitsNet.NanoFramework.ElectricInductance.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/ElectricPotential/UnitsNet.NanoFramework.ElectricPotential.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/ElectricPotentialAc/UnitsNet.NanoFramework.ElectricPotentialAc.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/ElectricPotentialChangeRate/UnitsNet.NanoFramework.ElectricPotentialChangeRate.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/ElectricPotentialDc/UnitsNet.NanoFramework.ElectricPotentialDc.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/ElectricResistance/UnitsNet.NanoFramework.ElectricResistance.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/ElectricResistivity/UnitsNet.NanoFramework.ElectricResistivity.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/ElectricSurfaceChargeDensity/UnitsNet.NanoFramework.ElectricSurfaceChargeDensity.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/Energy/UnitsNet.NanoFramework.Energy.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/EnergyDensity/UnitsNet.NanoFramework.EnergyDensity.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/Entropy/UnitsNet.NanoFramework.Entropy.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/Force/UnitsNet.NanoFramework.Force.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/ForceChangeRate/UnitsNet.NanoFramework.ForceChangeRate.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/ForcePerLength/UnitsNet.NanoFramework.ForcePerLength.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/Frequency/UnitsNet.NanoFramework.Frequency.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/FuelEfficiency/UnitsNet.NanoFramework.FuelEfficiency.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/HeatFlux/UnitsNet.NanoFramework.HeatFlux.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/HeatTransferCoefficient/UnitsNet.NanoFramework.HeatTransferCoefficient.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/Illuminance/UnitsNet.NanoFramework.Illuminance.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/Impulse/UnitsNet.NanoFramework.Impulse.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/Information/UnitsNet.NanoFramework.Information.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/Irradiance/UnitsNet.NanoFramework.Irradiance.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/Irradiation/UnitsNet.NanoFramework.Irradiation.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/Jerk/UnitsNet.NanoFramework.Jerk.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/KinematicViscosity/UnitsNet.NanoFramework.KinematicViscosity.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/LapseRate/UnitsNet.NanoFramework.LapseRate.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/LeakRate/UnitsNet.NanoFramework.LeakRate.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/Length/UnitsNet.NanoFramework.Length.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/Level/UnitsNet.NanoFramework.Level.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/LinearDensity/UnitsNet.NanoFramework.LinearDensity.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/LinearPowerDensity/UnitsNet.NanoFramework.LinearPowerDensity.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/Luminance/UnitsNet.NanoFramework.Luminance.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/Luminosity/UnitsNet.NanoFramework.Luminosity.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/LuminousFlux/UnitsNet.NanoFramework.LuminousFlux.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/LuminousIntensity/UnitsNet.NanoFramework.LuminousIntensity.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/MagneticField/UnitsNet.NanoFramework.MagneticField.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/MagneticFlux/UnitsNet.NanoFramework.MagneticFlux.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/Magnetization/UnitsNet.NanoFramework.Magnetization.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/Mass/UnitsNet.NanoFramework.Mass.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/MassConcentration/UnitsNet.NanoFramework.MassConcentration.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/MassFlow/UnitsNet.NanoFramework.MassFlow.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/MassFlux/UnitsNet.NanoFramework.MassFlux.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/MassFraction/UnitsNet.NanoFramework.MassFraction.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/MassMomentOfInertia/UnitsNet.NanoFramework.MassMomentOfInertia.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/Molality/UnitsNet.NanoFramework.Molality.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/MolarEnergy/UnitsNet.NanoFramework.MolarEnergy.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/MolarEntropy/UnitsNet.NanoFramework.MolarEntropy.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/MolarFlow/UnitsNet.NanoFramework.MolarFlow.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/MolarMass/UnitsNet.NanoFramework.MolarMass.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/Molarity/UnitsNet.NanoFramework.Molarity.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/Permeability/UnitsNet.NanoFramework.Permeability.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/Permittivity/UnitsNet.NanoFramework.Permittivity.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/PorousMediumPermeability/UnitsNet.NanoFramework.PorousMediumPermeability.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/Power/UnitsNet.NanoFramework.Power.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/PowerDensity/UnitsNet.NanoFramework.PowerDensity.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/PowerRatio/UnitsNet.NanoFramework.PowerRatio.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/Pressure/UnitsNet.NanoFramework.Pressure.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/PressureChangeRate/UnitsNet.NanoFramework.PressureChangeRate.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/Properties/AssemblyInfo.cs
    #	UnitsNet.NanoFramework/GeneratedCode/RadiationExposure/UnitsNet.NanoFramework.RadiationExposure.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/Radioactivity/UnitsNet.NanoFramework.Radioactivity.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/Ratio/UnitsNet.NanoFramework.Ratio.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/RatioChangeRate/UnitsNet.NanoFramework.RatioChangeRate.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/ReactiveEnergy/UnitsNet.NanoFramework.ReactiveEnergy.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/ReactivePower/UnitsNet.NanoFramework.ReactivePower.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/ReciprocalArea/UnitsNet.NanoFramework.ReciprocalArea.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/ReciprocalLength/UnitsNet.NanoFramework.ReciprocalLength.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/RelativeHumidity/UnitsNet.NanoFramework.RelativeHumidity.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/RotationalAcceleration/UnitsNet.NanoFramework.RotationalAcceleration.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/RotationalSpeed/UnitsNet.NanoFramework.RotationalSpeed.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/RotationalStiffness/UnitsNet.NanoFramework.RotationalStiffness.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/RotationalStiffnessPerLength/UnitsNet.NanoFramework.RotationalStiffnessPerLength.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/Scalar/UnitsNet.NanoFramework.Scalar.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/SolidAngle/UnitsNet.NanoFramework.SolidAngle.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/SpecificEnergy/UnitsNet.NanoFramework.SpecificEnergy.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/SpecificEntropy/UnitsNet.NanoFramework.SpecificEntropy.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/SpecificFuelConsumption/UnitsNet.NanoFramework.SpecificFuelConsumption.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/SpecificVolume/UnitsNet.NanoFramework.SpecificVolume.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/SpecificWeight/UnitsNet.NanoFramework.SpecificWeight.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/Speed/UnitsNet.NanoFramework.Speed.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/StandardVolumeFlow/UnitsNet.NanoFramework.StandardVolumeFlow.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/Temperature/UnitsNet.NanoFramework.Temperature.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/TemperatureChangeRate/UnitsNet.NanoFramework.TemperatureChangeRate.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/TemperatureDelta/UnitsNet.NanoFramework.TemperatureDelta.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/TemperatureGradient/UnitsNet.NanoFramework.TemperatureGradient.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/ThermalConductivity/UnitsNet.NanoFramework.ThermalConductivity.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/ThermalResistance/UnitsNet.NanoFramework.ThermalResistance.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/Torque/UnitsNet.NanoFramework.Torque.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/TorquePerLength/UnitsNet.NanoFramework.TorquePerLength.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/Turbidity/UnitsNet.NanoFramework.Turbidity.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/VitaminA/UnitsNet.NanoFramework.VitaminA.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/Volume/UnitsNet.NanoFramework.Volume.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/VolumeConcentration/UnitsNet.NanoFramework.VolumeConcentration.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/VolumeFlow/UnitsNet.NanoFramework.VolumeFlow.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/VolumeFlowPerArea/UnitsNet.NanoFramework.VolumeFlowPerArea.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/VolumePerLength/UnitsNet.NanoFramework.VolumePerLength.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/VolumetricHeatCapacity/UnitsNet.NanoFramework.VolumetricHeatCapacity.nuspec
    #	UnitsNet.NanoFramework/GeneratedCode/WarpingMomentOfInertia/UnitsNet.NanoFramework.WarpingMomentOfInertia.nuspec
    #	UnitsNet.NumberExtensions/GeneratedCode/NumberToIrradiationExtensions.g.cs
    #	UnitsNet.NumberExtensions/GeneratedCode/NumberToVolumeFlowExtensions.g.cs
    #	UnitsNet.NumberExtensions/UnitsNet.NumberExtensions.csproj
    #	UnitsNet/CustomCode/Quantities/Area.extra.cs
    #	UnitsNet/CustomCode/Quantities/Length.extra.cs
    #	UnitsNet/CustomCode/Quantities/TemperatureDelta.extra.cs
    #	UnitsNet/GeneratedCode/Quantities/BitRate.g.cs
    #	UnitsNet/GeneratedCode/Quantities/Information.g.cs
    #	UnitsNet/GeneratedCode/Quantities/Power.g.cs
    #	UnitsNet/UnitsNet.csproj

commit 0eb58d3
Author: Andreas Gullberg Larsen <[email protected]>
Date:   Thu Apr 4 18:41:05 2024 +0200

    👔Change nuget license from MIT to MIT-0 (angularsen#1381)

    Fixes angularsen#1379
    Backport from v6: angularsen#1380

    Change the license expression in the nugets to match the LICENSE file.
    Previously, nuget.org did not accept MIT-0 expression.

    ---------

    Co-authored-by: Muximize <[email protected]>

commit 3f71f26
Author: Travis Bement <[email protected]>
Date:   Thu Apr 4 12:38:00 2024 -0400

    Add operators for ReciprocalLength/-Area (v6) (angularsen#1385)

    Added additional operators that result in ReciprocalLength (Length/Area,
    Area/Volume) and ReciprocalArea (Length/Volume)

    (Mirrors functionality of v5 PR angularsen#1382)

    ---------

    Co-authored-by: Travis Bement <[email protected]>
    Co-authored-by: Andreas Gullberg Larsen <[email protected]>

commit 1b87682
Author: Travis Bement <[email protected]>
Date:   Thu Apr 4 12:27:32 2024 -0400

    Add operators for ReciprocalLength/-Area (angularsen#1382)

    Added additional operators that result in `ReciprocalLength`
    (Length/Area, Area/Volume) and `ReciprocalArea` (Length/Volume)

    Co-authored-by: Travis Bement <[email protected]>

commit b9b4365
Author: Muximize <[email protected]>
Date:   Thu Apr 4 18:24:11 2024 +0200

    Update Nuget dependencies (angularsen#1384)

commit 3b79a65
Author: Muximize <[email protected]>
Date:   Thu Apr 4 18:22:17 2024 +0200

    Change license from MIT to MIT-0 in NuspecGenerator (angularsen#1383)

commit 6c5d264
Author: Andreas Gullberg Larsen <[email protected]>
Date:   Thu Mar 28 00:34:35 2024 +0100

    JsonNet: 6.0.0-pre005

commit 1536509
Author: Andreas Gullberg Larsen <[email protected]>
Date:   Thu Mar 28 00:34:28 2024 +0100

    UnitsNet: 6.0.0-pre005

commit dc7d53c
Author: Andreas Gullberg Larsen <[email protected]>
Date:   Thu Mar 28 00:33:41 2024 +0100

    👔Change nuget license from MIT to MIT-0 (angularsen#1380)

    Fixes angularsen#1379

    Change the license expression in the nugets to match the LICENSE file.
    Previously, nuget.org did not accept MIT-0 expression.

commit 8519cb1
Author: Andreas Gullberg Larsen <[email protected]>
Date:   Tue Mar 12 20:23:37 2024 +0100

    JsonNet: 6.0.0-pre004

commit 28c534e
Author: Andreas Gullberg Larsen <[email protected]>
Date:   Tue Mar 12 20:23:31 2024 +0100

    UnitsNet: 6.0.0-pre004

commit 6c4faa9
Author: Andreas Gullberg Larsen <[email protected]>
Date:   Tue Mar 12 20:21:13 2024 +0100

    UnitsNet: 5.49.0

commit 1b47e7d
Author: Muximize <[email protected]>
Date:   Tue Mar 12 20:20:17 2024 +0100

    Upgrade to .NET 8 (angularsen#1375)

    As we're doing breaking changes in v6, it might be worth upgrading to the current [Long Term Support](https://dotnet.microsoft.com/en-us/platform/support/policy/dotnet-core) version of dotnet.

    This enables us to use C# 12 features and remove a bunch of conditional compilation (net 5328 deletions)

commit 6ab5f21
Author: Andreas Gullberg Larsen <[email protected]>
Date:   Sun Mar 3 20:45:46 2024 +0100

    JsonNet: 6.0.0-pre003

commit 0413634
Author: Andreas Gullberg Larsen <[email protected]>
Date:   Sun Mar 3 20:45:41 2024 +0100

    UnitsNet: 6.0.0-pre003

commit 6a9ae6c
Author: UrielZyx <[email protected]>
Date:   Sun Mar 3 21:44:35 2024 +0200

    Add type safety and improve type inference (angularsen#1374)

    Some of the extension methods in `UnitMath.cs` (e.g. Average) take an
    `Enum unitType` argument.
    The compiler should be able to detect when the units type doesn't match
    the quantity type.

    * This will break backwards compatibility, but only for:
      * People doing really weird things.
    * People using the explicit generic type instead of inference (e.g.
    `Average<Length>(LengthUnit.Inch)`), in which case they can fix the code
    by changing it to e.g. `Average<Length, LengthUnit>(LengthUnit.Inch)`
    * This change might be warranted in `UnitConverter.cs` as well, but
    can't be implemented as a straight-forward refactor since it breaks
    compatibility in generated code (e.g.
    `unitConverter.SetConversionFunction<ElectricPotential>` in
    `ElectricPotential` should be `SetConversionFunction<ElectricPotential,
    ElectricPotentialUnit>`

    In addition, had to remove a few unit tests that were asserting type
    safety.
    All tests that were removed:
    * Were only testing that an incorrect behavior throws an exception
    (`Assert.Throws`)
    * Don't compile after the changes in `UnitMath.cs`

commit aa61d5a
Author: Tim-Borcherding <[email protected]>
Date:   Fri Mar 1 21:23:27 2024 +0100

    Add TemperatureDelta / Duration = TemperatureChangeRate (angularsen#1370)

    Added missing operator to divide a TemperatureDelta by a time/duration
    to get the TemperatureChangeRate.

    ---------

    Co-authored-by: Andreas Gullberg Larsen <[email protected]>

commit d389213
Author: Andreas Gullberg Larsen <[email protected]>
Date:   Tue Feb 27 13:44:34 2024 +0100

    UnitsNet: 5.48.0

commit ace4fb4
Author: José Simões <[email protected]>
Date:   Tue Feb 27 12:42:49 2024 +0000

    Add MagenticField and Acceleration for .NET nanoFramework (angularsen#1369)

commit 4159603
Author: Andreas Gullberg Larsen <[email protected]>
Date:   Sat Feb 24 00:04:57 2024 +0100

    UnitsNet: 5.47.0

commit 7f2a39e
Author: Andreas Gullberg Larsen <[email protected]>
Date:   Fri Feb 23 23:11:12 2024 +0100

    README: Link to 6.x upgrade guide

commit 1b3647f
Author: Andreas Gullberg Larsen <[email protected]>
Date:   Sun Feb 18 17:54:23 2024 +0100

    nano: ✏️ Fix xmldoc of MaxValue, MinValue

commit 3a2a6e8
Author: Andreas Gullberg Larsen <[email protected]>
Date:   Sun Feb 18 15:31:56 2024 +0100

    UnitsNet: 5.46.0-pre

commit 91d8969
Author: Andreas Gullberg Larsen <[email protected]>
Date:   Sun Feb 18 15:30:53 2024 +0100

    fixup! Add Btu/ft² in irradiation (angularsen#1364)

    Fix remaining after rename.

commit ff39807
Author: Andreas Gullberg Larsen <[email protected]>
Date:   Sun Feb 18 15:28:52 2024 +0100

    Regen

commit 3b74e19
Author: Piotr Stenke <[email protected]>
Date:   Sat Feb 17 17:28:48 2024 +0100

    Add radiation equivalent dose (angularsen#1352)

    Added radiation equivalent dose and its two units - Sievert (SI-derived)
    and Roentgen equivalent man (or, simply, rem).

    Sievert comes with three prefixes - milli, micro, nano. This will
    support 99% of usecases, ranging from radiation caused by Earth itself
    (~6 to 83nSv/h, per this
    [article](https://www.epa.gov/radnet/about-exposure-and-dose-rates)),
    [eating bananas](https://en.wikipedia.org/wiki/Banana_equivalent_dose)
    (yep, that's a real unit), X-rays or tomography scans, as well as
    measuring health risk of radiation-induced cancer and radiation
    sickness.

    Roentgen equivalent man is mostly used in the US, and it can be easily
    converted to sieverts (1 sievert = 100 rems). It includes only one
    prefix - milli - as I did not find any sources with other prefixes being
    used.

    Wikipedia pages:

    https://en.wikipedia.org/wiki/Equivalent_dose
    https://en.wikipedia.org/wiki/Sievert
    https://en.wikipedia.org/wiki/Roentgen_equivalent_man
    https://en.wikipedia.org/wiki/Orders_of_magnitude_(radiation)

    ---------

    Co-authored-by: Piotr Stenke <[email protected]>

commit 85aec1b
Author: Andreas Gullberg Larsen <[email protected]>
Date:   Sat Feb 17 14:39:58 2024 +0100

    Regen

commit b1f88bf
Author: Mingbo Peng <[email protected]>
Date:   Sat Feb 17 21:39:24 2024 +0800

    Add Btu/ft² in irradiation (angularsen#1364)

    Added a new unit Btu/ft² in irradiation. This is commonly used in
    building industry.

    ---------

    Co-authored-by: Andreas Gullberg Larsen <[email protected]>

commit 545c8b9
Author: Andreas Gullberg Larsen <[email protected]>
Date:   Wed Feb 14 07:39:49 2024 +0100

    UnitsNet: 5.45.0-pre

commit c23cf15
Author: Andreas Gullberg Larsen <[email protected]>
Date:   Wed Feb 14 07:37:45 2024 +0100

    UnitsNet: UnitsNet/5.45.0-pre

commit d980ec1
Author: Andre Rodi <[email protected]>
Date:   Wed Feb 14 07:35:01 2024 +0100

    Add VolumeFlow prefixes Deca, Hecto (angularsen#1362)

    Fixes angularsen#1253

    Added the prefixes 'deca' and 'hecto', since, at least for the 'hecto'
    prefix, it's a very common unit used in the brewing industry. Added the
    'deca' prefix while I was at it.

    ---------

    Co-authored-by: André Rodi <[email protected]>

commit 6604660
Author: Andreas Gullberg Larsen <[email protected]>
Date:   Wed Feb 14 07:27:54 2024 +0100

    UnitsNet: 5.44.0-pre

    Pre-release of angularsen#1363

commit aa2a743
Author: Andreas Gullberg Larsen <[email protected]>
Date:   Wed Feb 14 07:26:22 2024 +0100

    💥🐛Change DataMember ordering to 1-indexed (angularsen#1360) (angularsen#1363)

    Related angularsen#1200
    Fixes angularsen#1356

    Apparently, protobuf-net does not support 0-indexed order values.

    - Change `DataMember` explicit order from 0-indexed to 1-indexed

    Some investigation indicates that the actual order value is not
    important, only the relative ordering:
    angularsen#1356 (comment)

    - WCF should tolerate this, according to its docs.
    angularsen#1356 (comment)
    - Binary formatters hopefully only care about relative ordering and thus
    still compatible?
    	- Protobuf-net, it never worked and should be OK
    -
    [BinaryFormatter](https://learn.microsoft.com/en-us/dotnet/api/system.runtime.serialization.formatters.binary.binaryformatter?view=net-8.0)
    is obsolete and generally not recommended for years, so hopefully no
    users are affected
    	- A bunch of others exist too, haven't looked into how they handle this
    - XML/JSON serializers should tolerate any order, can't imagine it
    breaking these?

commit e86eb17
Author: Andreas Gullberg Larsen <[email protected]>
Date:   Tue Jan 23 21:47:01 2024 +0100

    UnitsNet: 5.43.0

commit 6ffa8b1
Author: Andreas Gullberg Larsen <[email protected]>
Date:   Tue Jan 23 21:46:35 2024 +0100

    🐛Fix precision of Volume.CubicInch (angularsen#1358)

    Fixes angularsen#1357

    An imprecise value was used, fixed by using the definition of inch as 2.54e-2 per meter.
    Verified that the related unit CubicFoot is already precise.
@lipchev
Copy link
Collaborator Author

lipchev commented Apr 10, 2024

@angularsen I think the code is almost good- there a few more internals to optimize, but as far as the public API I think this cover all changes.

I've updated everything using the QuantityValue (which I've resurrected and extended), there are currently no public references to the Fraction type anywhere. I'll try to push whatever extensions might be useful to the original library, but generally speaking- we are only a few methods away from having the whole of the Fraction class implemented in the QuantityValue (at which point it would probably make sense for it to go into a separate project).

I've updated the PR to reflect the direction that I think this is heading into..

If you get the time, I this might be a good moment to pull-down my branch for a spin, and double-check that we are regression-free thus far (with the Tolerances still active). Currently there are only a handful of changes to the CustomCode/Tests so it should be relatively easy to review.

In the meanwhile, I'm going to see about fixing the open issues regarding the DataContract / NaN and the log-arithmetic which (I hope) are the only pain-points remaining..

PS Here are some numbers to look at (we should expect about the same from our own benchmarks).

@angularsen
Copy link
Owner

Sorry this is taking so long on my end, it's just crazy busy with work and family. I intend to get to this.

@lipchev
Copy link
Collaborator Author

lipchev commented May 17, 2024

Sorry this is taking so long on my end, it's just crazy busy with work and family. I intend to get to this.

Please note- I must have clicked the "synchronize" button at some point, which has merged the changes from the main branch.. 😊 Anyway, I've already prepared a cleaner version- where all tests are currently green, I'll post a new PR as soon as Fractions v8 is published.

@Muximize
Copy link
Contributor

I did not go through all of this thoroughly so maybe I'm missing something obvious, but I was wondering how this would compare to just replacing double wholesale with decimal. Would that (partially) solve the rounding/Equality/IComparable issues? I guess it would be favorable in terms of performance and memory usage, and not introducing an external dependency.

@lipchev
Copy link
Collaborator Author

lipchev commented Jun 16, 2024

I did not go through all of this thoroughly so maybe I'm missing something obvious, but I was wondering how this would compare to just replacing double wholesale with decimal. Would that (partially) solve the rounding/Equality/IComparable issues? I guess it would be favorable in terms of performance and memory usage, and not introducing an external dependency.

Assuming we're talking about a decimal that isn't constrained by size/precision - there would still be the matter of the non-terminating decimals such as the result of 1.0 / 3.0. So imagine this operation:

var oneThirdTheValue = value / 3;
var oneThirdTheValueTimesThree = oneThirdTheValue * 3;
Debug.Assert(oneThirdTheValueTimesThree == value)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
pinned Issues that should not be auto-closed due to inactivity.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants