{"id":13800182,"url":"https://github.com/typelevel/squants","last_synced_at":"2025-07-31T08:46:16.454Z","repository":{"id":14762947,"uuid":"17484323","full_name":"typelevel/squants","owner":"typelevel","description":"The Scala API for Quantities, Units of Measure and Dimensional Analysis","archived":false,"fork":false,"pushed_at":"2025-04-07T00:22:25.000Z","size":5303,"stargazers_count":928,"open_issues_count":62,"forks_count":121,"subscribers_count":18,"default_branch":"master","last_synced_at":"2025-05-07T08:30:12.270Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://www.squants.com","language":"Scala","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/typelevel.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2014-03-06T16:28:32.000Z","updated_at":"2025-04-30T22:29:18.000Z","dependencies_parsed_at":"2023-02-16T07:15:32.275Z","dependency_job_id":"b0109919-d0da-45a2-abea-90192d8f7837","html_url":"https://github.com/typelevel/squants","commit_stats":{"total_commits":465,"total_committers":63,"mean_commits":7.380952380952381,"dds":0.7677419354838709,"last_synced_commit":"5ad6433e8f7c92a274724d517e606cf53473ab68"},"previous_names":["garykeorkunian/squants"],"tags_count":22,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/typelevel%2Fsquants","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/typelevel%2Fsquants/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/typelevel%2Fsquants/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/typelevel%2Fsquants/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/typelevel","download_url":"https://codeload.github.com/typelevel/squants/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253036976,"owners_count":21844326,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-04T00:01:10.170Z","updated_at":"2025-07-31T08:46:16.406Z","avatar_url":"https://github.com/typelevel.png","language":"Scala","readme":"# Squants\n\n**The Scala API for Quantities, Units of Measure and Dimensional Analysis**\n\nSquants is a framework of data types and a domain specific language (DSL) for representing Quantities,\ntheir Units of Measure, and their Dimensional relationships.\nThe API supports typesafe dimensional analysis, improved domain models and more.\nAll types are immutable and thread-safe.\n\n[GitHub](https://github.com/typelevel/squants)\n|\n[Wiki](https://github.com/typelevel/squants/wiki)\n|\n[![Join the chat at https://gitter.im/typelevel/squants](https://badges.gitter.im/typelevel/squants.svg)](https://gitter.im/typelevel/squants?utm_source=badge\u0026utm_medium=badge\u0026utm_campaign=pr-badge\u0026utm_content=badge)\n|\n[![Scaladocs](https://www.javadoc.io/badge/org.typelevel/squants_2.13.svg?label=scaladoc)](https://static.javadoc.io/org.typelevel/squants_2.13/1.6.0/squants/index.html)\n|\n[![Build Status](https://travis-ci.org/typelevel/squants.png?branch=master)](https://travis-ci.org/typelevel/squants)\n\n\n### Current Versions\nCurrent Release: **1.6.0**\n([API Docs](https://oss.sonatype.org/service/local/repositories/releases/archive/org/typelevel/squants_2.13/1.6.0/squants_2.13-1.6.0-javadoc.jar/!/index.html#squants.package))\n\nDevelopment Build: **1.7.0-SNAPSHOT**\n([API Docs](https://oss.sonatype.org/service/local/repositories/snapshots/archive/org/typelevel/squants_2.13/1.6.0-SNAPSHOT/squants_2.13-1.7.0-SNAPSHOT-javadoc.jar/!/index.html#squants.package))\n\n[Release History](https://github.com/typelevel/squants/wiki/Release-History)\n\nBuild services provided by [Travis CI](https://travis-ci.com/)\n\nNOTE - This README reflects the feature set in the branch it can be found.\nFor more information on feature availability of a specific version see the Release History or the README for a that version\n\n## Installation\nRepository hosting for Squants is provided by [Sonatype](https://oss.sonatype.org/).\nTo use Squants in your SBT project add the following dependency to your build.\n\n    \"org.typelevel\"  %% \"squants\"  % \"1.6.0\"\nor\n\n    \"org.typelevel\"  %% \"squants\"  % \"1.7.0-SNAPSHOT\"\n\n\nTo use Squants in your Maven project add the following dependency\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003eorg.typelevel\u003c/groupId\u003e\n    \u003cartifactId\u003esquants_2.11\u003c/artifactId\u003e\n    \u003cversion\u003e1.6.0\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nBeginning with Squants 0.4.x series, both Scala 2.10 and 2.11 builds are available.\nBeginning with Squants 1.x series, Scala 2.11, 2.12 and 2.13 builds are available.\nScala.js is supported on version 0.6.31 and 1.0.0-RC1\n\nTo use Squants interactively in the Scala REPL, clone the git repo and run `sbt squantsJVM/console`\n\n    git clone https://github.com/typelevel/squants\n    cd squants\n    sbt squantsJVM/console\n\n## Third-party integrations\n\nThis is an incomplete list of third-party libraries that support squants:\n\n* [PureConfig](https://github.com/melrief/pureconfig/)\n* [Ciris](https://cir.is/)\n\nIf your library isn't listed here, please open a PR to add it!\n\n## Type Safe Dimensional Analysis\n*The Trouble with Doubles*\n\nWhen building programs that perform dimensional analysis, developers are quick to declare\nquantities using a basic numeric type, usually Double.  While this may be satisfactory in some situations,\nit can often lead to semantic and other logic issues.\n\nFor example, when using a Double to describe quantities of Energy (kWh) and Power (kW), it is possible\nto compile a program that adds these two values together.  This is not appropriate as kW and kWh\nmeasure quantities of two different dimensions.  The unit kWh is used to measure an amount of Energy used\nor produced.  The unit kW is used to measure Power/Load, the rate at which Energy is being used\nor produced, that is, Power is the first time derivative of Energy.\n\n*Power = Energy / Time*\n\nConsider the following code:\n\n```scala\nscala\u003e val loadKw = 1.2\nloadKw: Double = 1.2\n\nscala\u003e val energyMwh = 24.2\nenergyMwh: Double = 24.2\n\nscala\u003e val sumKw = loadKw + energyMwh\nsumKw: Double = 25.4\n```\n\nThis example not only adds quantities of different dimensions (Power vs Energy),\nit also fails to convert the scales implied in the val names (Mega vs Kilo).\nBecause this code compiles, detection of these errors is pushed further into the development cycle.\n\n### Dimensional Type Safety\n\n_Only quantities with the same dimensions may be compared, equated, added, or subtracted._\n\nSquants helps prevent errors like these by type checking operations at compile time and\nautomatically applying scale and type conversions at run-time.  For example:\n\n```scala\nscala\u003e import squants.energy.{Kilowatts, Megawatts, Power}\nimport squants.energy.{Kilowatts, Megawatts, Power}\n\nscala\u003e val load1: Power = Kilowatts(12)\nload1: squants.energy.Power = 12.0 kW\n\nscala\u003e val load2: Power = Megawatts(0.023)\nload2: squants.energy.Power = 0.023 MW\n\nscala\u003e val sum = load1 + load2\nsum: squants.energy.Power = 35.0 kW\n\nscala\u003e sum == Kilowatts(35)\nres0: Boolean = true\n\nscala\u003e sum == Megawatts(0.035) // comparisons automatically convert scale\nres1: Boolean = true\n```\n\nThe above sample works because Kilowatts and Megawatts are both units of Power.  Only the scale is\ndifferent and the library applies an appropriate conversion.  Also, notice that keeping track of\nthe scale within the value name is no longer needed:\n\n```scala\nscala\u003e import squants.energy.{Energy, Power, Kilowatts, KilowattHours}\nimport squants.energy.{Energy, Power, Kilowatts, KilowattHours}\n\nscala\u003e val load: Power = Kilowatts(1.2)\nload: squants.energy.Power = 1.2 kW\n\nscala\u003e val energy: Energy = KilowattHours(23.0)\nenergy: squants.energy.Energy = 23.0 kWh\n```\n\nInvalid operations, like adding power and energy, no longer compile:\n```scala\nscala\u003e val sum = load + energy\n\u003cconsole\u003e:16: error: type mismatch;\n found   : squants.energy.Energy\n required: squants.energy.Power\n       val sum = load + energy\n                        ^\n```\nBy using stronger types, we catch the error earlier in the development cycle, preventing the error made when using Double in the example above.\n\n### Dimensionally Correct Type Conversions\n\n_One may take quantities with different dimensions, and multiply or divide them._\n\nDimensionally correct type conversions are a key feature of Squants.\nConversions are implemented by defining relationships between Quantity types using the `*` and `/` operators.\n\nCode samples in this section assume these imports:\n```scala\nimport squants.energy.{Kilowatts, Power}\nimport squants.time.{Hours, Days}\n```\n\nThe following code demonstrates creating ratio between two quantities of the same dimension,\nresulting in a dimensionless value:\n\n```scala\nscala\u003e val ratio = Days(1) / Hours(3)\nratio: Double = 8.0\n```\n\nThis code demonstrates use of the `Power.*` method that takes a `Time` and returns an `Energy`:\n\n```scala\nscala\u003e val load = Kilowatts(1.2)\nload: squants.energy.Power = 1.2 kW\n\nscala\u003e val time = Hours(2)\ntime: squants.time.Time = 2.0 h\n\nscala\u003e val energyUsed = load * time\nenergyUsed: squants.energy.Energy = 2400.0 Wh\n```\n\nThis code demonstrates use of the `Energy./` method that takes a `Time` and returns a `Power`:\n\n```scala\nscala\u003e val aveLoad: Power = energyUsed / time\naveLoad: squants.energy.Power = 1200.0 W\n```\n\n### Unit Conversions\n\nCode samples in this section assume these imports:\n```scala\nimport scala.language.postfixOps\nimport squants.energy.{Gigawatts, Kilowatts, Power, Megawatts}\nimport squants.mass.MassConversions._\nimport squants.mass.{Kilograms, Pounds}\nimport squants.thermal.TemperatureConversions._\nimport squants.thermal.Fahrenheit\n```\n\nQuantity values are based in the units used to create them.\n\n```scala\nscala\u003e val loadA: Power = Kilowatts(1200)\nloadA: squants.energy.Power = 1200.0 kW\n\nscala\u003e val loadB: Power = Megawatts(1200)\nloadB: squants.energy.Power = 1200.0 MW\n```\n\nSince Squants properly equates values of a like dimension, regardless of the unit,\nthere is usually no reason to explicitly convert from one to the other.\nThis is especially true if the user code is primarily performing dimensional analysis.\n\nHowever, there are times when you may need to set a Quantity value to a specific unit (eg, for proper JSON encoding).\n\nWhen necessary, a quantity can be converted to another unit using the `in` method.\n\n```scala\nscala\u003e val loadA = Kilowatts(1200)\nloadA: squants.energy.Power = 1200.0 kW\n\nscala\u003e val loadB = loadA in Megawatts\nloadB: squants.energy.Power = 1.2 MW\n\nscala\u003e val loadC = loadA in Gigawatts\nloadC: squants.energy.Power = 0.0012 GW\n```\n\nSometimes you need to get the numeric value of the quantity in a specific unit\n(eg, for submission to an external service that requires a numeric in a specified unit\nor to perform analysis beyond Squant's domain)\n\nWhen necessary, the value can be extracted in the desired unit with the `to` method.\n\n```scala\nscala\u003e val load: Power = Kilowatts(1200)\nload: squants.energy.Power = 1200.0 kW\n\nscala\u003e val kw: Double = load to Kilowatts\nkw: Double = 1200.0\n\nscala\u003e val mw: Double = load to Megawatts\nmw: Double = 1.2\n\nscala\u003e val gw: Double = load to Gigawatts\ngw: Double = 0.0012\n```\n\nMost types include methods with convenient aliases for the `to` methods.\n\n```scala\nscala\u003e val kw: Double = load toKilowatts\nkw: Double = 1200.0\n\nscala\u003e val mw: Double = load toMegawatts\nmw: Double = 1.2\n\nscala\u003e val gw: Double = load toGigawatts\ngw: Double = 0.0012\n```\n\nNOTE - It is important to use the `to` method for extracting the numeric value,\nas this ensures you will be getting the numeric value for the desired unit.\n`Quantity.value` should not be accessed directly.\nTo prevent improper usage, direct access to the `Quantity.value` field may be deprecated in a future version.\n\nCreating strings formatted in the desired unit:\n\n```scala\nscala\u003e val kw: String = load toString Kilowatts\nkw: String = 1200.0 kW\n\nscala\u003e val mw: String = load toString Megawatts\nmw: String = 1.2 MW\n\nscala\u003e val gw: String = load toString Gigawatts\ngw: String = 0.0012 GW\n```\n\nCreating `Tuple2[Double, String]` that includes a numeric value and unit symbol:\n\n```scala\nscala\u003e val load: Power = Kilowatts(1200)\nload: squants.energy.Power = 1200.0 kW\n\nscala\u003e val kw = load toTuple\nkw: (Double, String) = (1200.0,kW)\n\nscala\u003e val mw = load toTuple Megawatts\nmw: (Double, String) = (1.2,MW)\n\nscala\u003e val gw = load toTuple Gigawatts\ngw: (Double, String) = (0.0012,GW)\n```\n\nThis can be useful for passing properly scaled quantities to other processes\nthat do not use Squants, or require use of more basic types (Double, String)\n\nSimple console based conversions (using DSL described below)\n\n```scala\nscala\u003e 1.kilograms to Pounds\nres0: Double = 2.2046226218487757\n\nscala\u003e kilogram / pound\nres1: Double = 2.2046226218487757\n\nscala\u003e 2.1.pounds to Kilograms\nres2: Double = 0.952543977\n\nscala\u003e 2.1.pounds / kilogram\nres3: Double = 0.9525439770000002\n\nscala\u003e 100.C to Fahrenheit\nres4: Double = 212.0\n```\n\n### Mapping over Quantity values\nApply a `Double =\u003e Double` operation to the underlying value of a quantity, while preserving its type and unit.\n\n```scala\nscala\u003e import squants.energy.Kilowatts\nimport squants.energy.Kilowatts\n\nscala\u003e val load = Kilowatts(2.0)\nload: squants.energy.Power = 2.0 kW\n\nscala\u003e val newLoad = load.map(v =\u003e v * 2 + 10)\nnewLoad: squants.energy.Power = 14.0 kW\n```\n\nThe `q.map(f)` method effectively expands to `q.unit(f(q.to(q.unit))`\n\nNOTE - For Money objects, use the `mapAmount` method as this will retain the BigDecimal precision used there.\n\n### Approximations\nCreate an implicit Quantity value to be used as a tolerance in approximations.\nThen use the `approx` method (or `=~`, `~=`, `≈` operators) like you would use the `equals` method (`==` operator).\n\n```scala\nscala\u003e import squants.energy.{Kilowatts, Watts}\nimport squants.energy.{Kilowatts, Watts}\n\nscala\u003e val load = Kilowatts(2.0)\nload: squants.energy.Power = 2.0 kW\n\nscala\u003e val reading = Kilowatts(1.9999)\nreading: squants.energy.Power = 1.9999 kW\n```\n\nCalls to `approx` (and its symbolic aliases) use an implicit tolerance:\n\n```scala\nscala\u003e implicit val tolerance = Watts(.1)\ntolerance: squants.energy.Power = 0.1 W\n\nscala\u003e load =~ reading\nres0: Boolean = true\n\nscala\u003e load ≈ reading\nres1: Boolean = true\n\nscala\u003e load approx reading\nres2: Boolean = true\n```\n\nThe `=~` and `≈` are the preferred operators as they have the correct precedence for equality operations.\nThe `~=` is provided for those who wish to use a more natural looking approx operator using standard characters.\nHowever, because of its lower precedence, user code may require parenthesis around these comparisons.\n\n### Vectors\n\nAll `Quantity` types in Squants represent the scalar value of a quantity.\nThat is, there is no direction information encoded in any of the Quantity types.\nThis is true even for Quantities which are normally vector quantities (ie. Velocity, Acceleration, etc).\n\nVector quantities in Squants are implemented as case classes that takes a variable parameter list of like quantities\nrepresenting a set of point coordinates in Cartesian space.\nThe SVector object is a factory for creating DoubleVectors and QuantityVectors.\nThe dimensionality of the vector is determined by the number of arguments.\nMost basic vector operations are currently supported (addition, subtraction, scaling, cross and dot products)\n\n```scala\nscala\u003e import squants.{QuantityVector, SVector}\nimport squants.{QuantityVector, SVector}\n\nscala\u003e import squants.space.{Kilometers, Length}\nimport squants.space.{Kilometers, Length}\n\nscala\u003e import squants.space.LengthConversions._\nimport squants.space.LengthConversions._\n\nscala\u003e val vector: QuantityVector[Length] = SVector(Kilometers(1.2), Kilometers(4.3), Kilometers(2.3))\nvector: squants.QuantityVector[squants.space.Length] = QuantityVector(WrappedArray(1.2 km, 4.3 km, 2.3 km))\n\nscala\u003e val magnitude: Length = vector.magnitude        // returns the scalar value of the vector\nmagnitude: squants.space.Length = 5.021951811795888 km\n\nscala\u003e val normalized = vector.normalize(Kilometers)   // returns a corresponding vector scaled to 1 of the given unit\nnormalized: vector.SVectorType = QuantityVector(ArrayBuffer(0.2389509188800581 km, 0.8562407926535415 km, 0.45798926118677796 km))\n\nscala\u003e val vector2: QuantityVector[Length] = SVector(Kilometers(1.2), Kilometers(4.3), Kilometers(2.3))\nvector2: squants.QuantityVector[squants.space.Length] = QuantityVector(WrappedArray(1.2 km, 4.3 km, 2.3 km))\n\nscala\u003e val vectorSum = vector + vector2        // returns the sum of two vectors\nvectorSum: vector.SVectorType = QuantityVector(ArrayBuffer(2.4 km, 8.6 km, 4.6 km))\n\nscala\u003e val vectorDiff = vector - vector2       // return the difference of two vectors\nvectorDiff: vector.SVectorType = QuantityVector(ArrayBuffer(0.0 km, 0.0 km, 0.0 km))\n\nscala\u003e val vectorScaled = vector * 5           // returns vector scaled 5 times\nvectorScaled: vector.SVectorType = QuantityVector(ArrayBuffer(6.0 km, 21.5 km, 11.5 km))\n\nscala\u003e val vectorReduced = vector / 5          // returns vector reduced 5 time\nvectorReduced: vector.SVectorType = QuantityVector(ArrayBuffer(0.24 km, 0.86 km, 0.45999999999999996 km))\n\nscala\u003e val vectorDouble = vector / 5.meters    // returns vector reduced and converted to DoubleVector\nvectorDouble: squants.DoubleVector = DoubleVector(ArrayBuffer(240.0, 860.0, 459.99999999999994))\n\nscala\u003e val dotProduct = vector * vectorDouble  // returns the Dot Product of vector and vectorDouble\ndotProduct: squants.space.Length = 5044.0 km\n\nscala\u003e val crossProduct = vector crossProduct vectorDouble  // currently only supported for 3-dimensional vectors\ncrossProduct: vector.SVectorType = QuantityVector(WrappedArray(0.0 km, 1.1368683772161603E-13 km, 0.0 km))\n```\n\nSimple non-quantity (Double based) vectors are also supported.\n\n```scala\nimport squants.DoubleVector\n\nval vector: DoubleVector = SVector(1.2, 4.3, 2.3, 5.4)   // a Four-dimensional vector\n```\n\n#### Dimensional conversions within Vector operations.\n\nCurrently dimensional conversions are supported by using the slightly verbose, but flexible map method.\n\n```scala\nscala\u003e import squants.{DoubleVector, QuantityVector}\nimport squants.{DoubleVector, QuantityVector}\n\nscala\u003e import squants.motion.Velocity\nimport squants.motion.Velocity\n\nscala\u003e import squants.space.{Area, Kilometers, Length, Meters}\nimport squants.space.{Area, Kilometers, Length, Meters}\n\nscala\u003e import squants.time.Seconds\nimport squants.time.Seconds\n\nscala\u003e val vectorLength = QuantityVector(Kilometers(1.2), Kilometers(4.3), Kilometers(2.3))\nvectorLength: squants.QuantityVector[squants.space.Length] = QuantityVector(WrappedArray(1.2 km, 4.3 km, 2.3 km))\n\nscala\u003e val vectorArea = vectorLength.map[Area](_ * Kilometers(2))      // QuantityVector(2.4 km², 8.6 km², 4.6 km²)\nvectorArea: squants.QuantityVector[squants.space.Area] = QuantityVector(ArrayBuffer(2.4 km², 8.6 km², 4.6 km²))\n\nscala\u003e val vectorVelocity = vectorLength.map[Velocity](_ / Seconds(1)) // QuantityVector(1200.0 m/s, 4300.0 m/s, 2300.0 m/s)\nvectorVelocity: squants.QuantityVector[squants.motion.Velocity] = QuantityVector(ArrayBuffer(1200.0 m/s, 4300.0 m/s, 2300.0 m/s))\n\nscala\u003e val vectorDouble = DoubleVector(1.2, 4.3, 2.3)\nvectorDouble: squants.DoubleVector = DoubleVector(WrappedArray(1.2, 4.3, 2.3))\n\nscala\u003e val vectorLength = vectorDouble.map[Length](Kilometers(_))      // QuantityVector(1.2 km, 4.3 km, 2.3 km)\nvectorLength: squants.QuantityVector[squants.space.Length] = QuantityVector(ArrayBuffer(1.2 km, 4.3 km, 2.3 km))\n```\n\nConvert QuantityVectors to specific units using the `to` or `in` method - much like Quantities.\n\n```scala\nscala\u003e val vectorLength = QuantityVector(Kilometers(1.2), Kilometers(4.3), Kilometers(2.3))\nvectorLength: squants.QuantityVector[squants.space.Length] = QuantityVector(WrappedArray(1.2 km, 4.3 km, 2.3 km))\n\nscala\u003e val vectorMetersNum = vectorLength.to(Meters)   // DoubleVector(1200.0, 4300.0, 2300.0)\nvectorMetersNum: squants.DoubleVector = DoubleVector(ArrayBuffer(1200.0, 4300.0, 2300.0))\n\nscala\u003e val vectorMeters = vectorLength.in(Meters)      // QuantityVector(1200.0 m, 4300.0 m, 2300.0 m)\nvectorMeters: squants.QuantityVector[squants.space.Length] = QuantityVector(ArrayBuffer(1200.0 m, 4300.0 m, 2300.0 m))\n```\n\n## Market Package\nMarket Types are similar but not quite the same as other quantities in the library.\nThe primary type, Money, is a Dimensional Quantity, and its Units of Measure are Currencies.\nHowever, because the conversion multipliers between currency units can not be predefined,\nmany of the behaviors have been overridden and augmented to realize correct behavior.\n\n### Money\nA Quantity of purchasing power measured in Currency units.\nLike other quantities, the Unit of Measures are used to create Money values.\n\n```scala\nscala\u003e import squants.market.{BTC, JPY, USD, XAU}\nimport squants.market.{BTC, JPY, USD, XAU}\n\nscala\u003e val tenBucks = USD(10)      // Money: 10 USD\ntenBucks: squants.market.Money = 1E+1 USD\n\nscala\u003e val someYen = JPY(1200)     // Money: 1200 JPY\nsomeYen: squants.market.Money = 1.2E+3 JPY\n\nscala\u003e val goldStash = XAU(50)     // Money: 50 XAU\ngoldStash: squants.market.Money = 5E+1 XAU\n\nscala\u003e val digitalCache = BTC(50)  // Money: 50 BTC\ndigitalCache: squants.market.Money = 5E+1 BTC\n```\n\n### Price\nA Ratio between Money and another Quantity.\nA Price value is typed on a Quantity and can be denominated in any defined Currency.\n\n*Price = Money / Quantity*\n\nAssuming these imports:\n```scala\nimport squants.{Dozen, Each}\nimport squants.energy.MegawattHours\nimport squants.market.USD\nimport squants.space.UsGallons\n```\n\nYou can compute the following:\n```scala\nscala\u003e val threeForADollar = USD(1) / Each(3)\nthreeForADollar: squants.market.Price[squants.Dimensionless] = 1 USD/3.0 ea\n\nscala\u003e val energyPrice = USD(102.20) / MegawattHours(1)\nenergyPrice: squants.market.Price[squants.energy.Energy] = 102.2 USD/1.0 MWh\n\nscala\u003e val milkPrice = USD(4) / UsGallons(1)\nmilkPrice: squants.market.Price[squants.space.Volume] = 4 USD/1.0 gal\n\nscala\u003e val costForABunch = threeForADollar * Dozen(10)\ncostForABunch: squants.market.Money = 4E+1 USD\n\nscala\u003e val energyCost = energyPrice * MegawattHours(4)\nenergyCost: squants.market.Money = 408.8 USD\n\nscala\u003e val milkQuota = USD(20) / milkPrice\nmilkQuota: squants.space.Volume = 5.0 gal\n```\n\nConversions to Strings\n```scala\nscala\u003e val money = USD(123.456)\nmoney: squants.market.Money = 123.456 USD\n\nscala\u003e val s = money.toString  // returns full precision amount with currency code\ns: String = 123.456 USD\n\nscala\u003e val s = money.toFormattedString // returns currency symbol and amount rounded based on currency rules\ns: String = $123.46\n```\n\n### FX Support\nCurrency Exchange Rates are used to define the conversion factors between currencies\n\n```scala\nscala\u003e import squants.market.{CurrencyExchangeRate, JPY, Money, USD}\nimport squants.market.{CurrencyExchangeRate, JPY, Money, USD}\n\nscala\u003e // create an exchange rate\n     | val rate1 = CurrencyExchangeRate(USD(1), JPY(100))\nrate1: squants.market.CurrencyExchangeRate = USD/JPY 100.0\n\nscala\u003e // OR\n     | val rate2 = USD / JPY(100)\nrate2: squants.market.CurrencyExchangeRate = USD/JPY 100.0\n\nscala\u003e // OR\n     | val rate3 = JPY(100) -\u003e USD(1)\nrate3: squants.market.CurrencyExchangeRate = USD/JPY 100.0\n\nscala\u003e // OR\n     | val rate4 = JPY(100) toThe USD(1)\nrate4: squants.market.CurrencyExchangeRate = USD/JPY 100.0\n\nscala\u003e val someYen: Money = JPY(350)\nsomeYen: squants.market.Money = 3.5E+2 JPY\n\nscala\u003e val someBucks: Money = USD(23.50)\nsomeBucks: squants.market.Money = 23.5 USD\n```\n\nUse the `convert` method which automatically converts the money to the 'other' currency:\n\n```scala\nscala\u003e val dollarAmount: Money = rate1.convert(someYen)\ndollarAmount: squants.market.Money = 3.5 USD\n\nscala\u003e val yenAmount: Money = rate1.convert(someBucks)\nyenAmount: squants.market.Money = 2.35E+3 JPY\n```\n\nOr just use the `*` operator in either direction (money * rate, or rate * money):\n```scala\nscala\u003e val dollarAmount2: Money = rate1 * someYen\ndollarAmount2: squants.market.Money = 3.5 USD\n\nscala\u003e val yenAmount2: Money = someBucks * rate1\nyenAmount2: squants.market.Money = 2.35E+3 JPY\n```\n\n### Money Context\nA MoneyContext can be implicitly declared to define default settings and applicable exchange rates within its scope.\nThis allows your application to work with a default currency based on an application configuration or other dynamic source.\nIt also provides support for updating exchange rates and using those rates for automatic conversions between currencies.\nThe technique and frequency chosen for exchange rate updates is completely in control of the application.\n\nAssuming these imports:\n```scala\nimport squants.energy.MegawattHours\nimport squants.market.{CAD, JPY, MXN, USD}\nimport squants.market.defaultMoneyContext\n```\n\nYou can compute:\n```scala\nscala\u003e val exchangeRates = List(USD / CAD(1.05), USD / MXN(12.50), USD / JPY(100))\nexchangeRates: List[squants.market.CurrencyExchangeRate] = List(USD/CAD 1.05, USD/MXN 12.5, USD/JPY 100.0)\n\nscala\u003e implicit val moneyContext = defaultMoneyContext withExchangeRates exchangeRates\nmoneyContext: squants.market.MoneyContext = MoneyContext(DefaultCurrency(USD),Currencies(ARS,AUD,BRL,BTC,CAD,CHF,CLP,CNY,CZK,DKK,ETH,EUR,GBP,HKD,INR,JPY,KRW,LTC,MXN,MYR,NAD,NOK,NZD,RUB,SEK,USD,XAG,XAU,ZAR),ExchangeRates(USD/CAD 1.05,USD/JPY 100.0,USD/MXN 12.5),AllowIndirectConversions(true))\n\nscala\u003e val energyPrice = USD(102.20) / MegawattHours(1)\nenergyPrice: squants.market.Price[squants.energy.Energy] = 102.2 USD/1.0 MWh\n\nscala\u003e val someMoney = Money(350) // 350 in the default Cur\nsomeMoney: squants.market.Money = 3.5E+2 USD\n\nscala\u003e val usdMoney: Money = someMoney in USD\nusdMoney: squants.market.Money = 3.5E+2 USD\n\nscala\u003e val usdBigDecimal: BigDecimal = someMoney to USD\nusdBigDecimal: BigDecimal = 350.0\n\nscala\u003e val yenCost: Money = (energyPrice * MegawattHours(5)) in JPY\nyenCost: squants.market.Money = 5.11E+4 JPY\n\nscala\u003e val northAmericanSales: Money = (CAD(275) + USD(350) + MXN(290)) in USD\nnorthAmericanSales: squants.market.Money = 635.1047619047619047619047619047619 USD\n```\n\n## Quantity Ranges\nA `QuantityRange` is used to represent a range of Quantity values between an upper and lower bound:\n\n```scala\nimport squants.QuantityRange\nimport squants.energy.{Kilowatts, Megawatts, Power}\n```\n```scala\nval load1: Power = Kilowatts(1000)\n// load1: squants.energy.Power = 1000.0 kW\n\nval load2: Power = Kilowatts(5000)\n// load2: squants.energy.Power = 5000.0 kW\n\nval range: QuantityRange[Power] = QuantityRange(load1, load2)\n// range: squants.QuantityRange[squants.energy.Power] = QuantityRange(1000.0 kW,5000.0 kW)\n```\n\n### Inclusivity and Exclusivitiy\n\nThe `QuantityRange` constructor requires that `upper` is strictly greater than `lower`:\n\n```scala\nimport squants.space.LengthConversions._\n// import squants.space.LengthConversions._\n\n// this will work b/c upper \u003e lower\nQuantityRange(1.km, 5.km)\n// res1: squants.QuantityRange[squants.space.Length] = QuantityRange(1.0 km,5.0 km)\n```\n\nThis will fail because `lower` = `upper`:\n\n```scala\nscala\u003e QuantityRange(1.km, 1.km)\njava.lang.IllegalArgumentException: QuantityRange upper bound must be strictly greater than to the lower bound\n  at squants.QuantityRange.\u003cinit\u003e(QuantityRange.scala:25)\n  ... 43 elided\n```\n\n`QuantityRange` contains two functions that check if an element is part of the range, `contains` and `includes`.\nThese differ in how they treat the range's upper bound: `contains()` _excludes_ it but `includes()` _includes_ it.\n\n```scala\nscala\u003e val distances = QuantityRange(1.km, 5.km)\ndistances: squants.QuantityRange[squants.space.Length] = QuantityRange(1.0 km,5.0 km)\n\nscala\u003e distances.contains(5.km) // this is false b/c contains() doesn't include the upper range\nres3: Boolean = false\n\nscala\u003e distances.includes(5.km) // this is true b/c includes() does include the upper range\nres4: Boolean = true\n```\n\n### QuantityRange transformation\n\nThe multiplication and division operators create a `Seq` of ranges from the original.\n\nFor example:\n\nCreate a Seq of 10 sequential ranges starting with the original and each the same size as the original:\n```scala\nval rs1 = range * 10\n// rs1: squants.QuantitySeries[squants.energy.Power] = Vector(QuantityRange(1000.0 kW,5000.0 kW), QuantityRange(5000.0 kW,9000.0 kW), QuantityRange(9000.0 kW,13000.0 kW), QuantityRange(13000.0 kW,17000.0 kW), QuantityRange(17000.0 kW,21000.0 kW), QuantityRange(21000.0 kW,25000.0 kW), QuantityRange(25000.0 kW,29000.0 kW), QuantityRange(29000.0 kW,33000.0 kW), QuantityRange(33000.0 kW,37000.0 kW), QuantityRange(37000.0 kW,41000.0 kW))\n```\nCreate a Seq of 10 sequential ranges each 1/10th of the original size:\n\n```scala\nval rs2 = range / 10\n// rs2: squants.QuantitySeries[squants.energy.Power] = Vector(QuantityRange(1000.0 kW,1400.0 kW), QuantityRange(1400.0 kW,1800.0 kW), QuantityRange(1800.0 kW,2200.0 kW), QuantityRange(2200.0 kW,2600.0 kW), QuantityRange(2600.0 kW,3000.0 kW), QuantityRange(3000.0 kW,3400.0 kW), QuantityRange(3400.0 kW,3800.0 kW), QuantityRange(3800.0 kW,4200.0 kW), QuantityRange(4200.0 kW,4600.0 kW), QuantityRange(4600.0 kW,5000.0 kW))\n```\n\nCreate a Seq of 10 sequential ranges each with a size of 400 kilowatts:\n```scala\nval rs3 = range / Kilowatts(400)\n// rs3: squants.QuantitySeries[squants.energy.Power] = Vector(QuantityRange(1000.0 kW,1400.0 kW), QuantityRange(1400.0 kW,1800.0 kW), QuantityRange(1800.0 kW,2200.0 kW), QuantityRange(2200.0 kW,2600.0 kW), QuantityRange(2600.0 kW,3000.0 kW), QuantityRange(3000.0 kW,3400.0 kW), QuantityRange(3400.0 kW,3800.0 kW), QuantityRange(3800.0 kW,4200.0 kW), QuantityRange(4200.0 kW,4600.0 kW), QuantityRange(4600.0 kW,5000.0 kW))\n```\n\n### QuantityRange operations\n\n`QuantityRange` supports foreach, map, and foldLeft/foldRight. These vary slightly from the versions\nin the Scala standard library in that they take a divisior as the first parameter. The examples below\nillustrate their use.\n\nSubdivide range into 1-Megawatt \"slices\", and foreach over each of slices:\n```scala\nrange.foreach(Megawatts(1)) { r =\u003e println(s\"lower = ${r.lower}, upper = ${r.upper}\") }\n// lower = 1000.0 kW, upper = 2000.0 kW\n// lower = 2000.0 kW, upper = 3000.0 kW\n// lower = 3000.0 kW, upper = 4000.0 kW\n// lower = 4000.0 kW, upper = 5000.0 kW\n```\n\nSubdivide range into 10 slices and map over each slice:\n```scala\nrange.map(10) { r =\u003e r.upper }\n// res6: Seq[squants.energy.Power] = Vector(1400.0 kW, 1800.0 kW, 2200.0 kW, 2600.0 kW, 3000.0 kW, 3400.0 kW, 3800.0 kW, 4200.0 kW, 4600.0 kW, 5000.0 kW)\n```\n\nSubdivide range into 10 slices and fold over them, using 0 Megawatts as a starting value:\n```scala\nrange.foldLeft(10, Megawatts(0)) { (z, r) =\u003e z + r.upper }\n// res7: squants.energy.Power = 32.0 MW\n```\n\nNOTE - Because these implementations of foreach, map and fold* take a parameter (the divisor), these methods\nare not directly compatible with Scala's for comprehensions.\nTo use in a for comprehension, apply the * or / operators as described above to create a Seq from the Range.\n\n```scala\nfor {\n    interval \u003c- (0.seconds to 1.seconds) * 60  // 60 time ranges, 0s to 1s, 1s to 2s, ...., 59s to 60s\n    ...\n} yield ...\n```\n\n## Natural Language DSL\nImplicit conversions give the DSL some features that allows user code to express quantities in a\nmore naturally expressive and readable way.\n\nCode samples in this section assume these imports\n```scala\nimport squants.energy.{Kilowatts, MegawattHours, Power}\nimport squants.market.{Price, USD}\nimport squants.time.Hours\n```\n\nCreate Quantities using Unit Of Measure Factory objects (no implicits required):\n\n```scala\nscala\u003e val load = Kilowatts(100)\nload: squants.energy.Power = 100.0 kW\n\nscala\u003e val time = Hours(3.75)\ntime: squants.time.Time = 3.75 h\n\nscala\u003e val money = USD(112.50)\nmoney: squants.market.Money = 112.5 USD\n\nscala\u003e val price = Price(money, MegawattHours(1))\nprice: squants.market.Price[squants.energy.Energy] = 112.5 USD/1.0 MWh\n```\n\nCreate Quantities using Unit of Measure names and/or symbols (uses implicits):\n\n```scala\nimport scala.language.postfixOps\nimport squants.energy.EnergyConversions._\nimport squants.energy.PowerConversions._\nimport squants.information.InformationConversions._\nimport squants.market.MoneyConversions._\nimport squants.space.LengthConversions._\nimport squants.time.TimeConversions._\n```\n```scala\nscala\u003e val load1 = 100 kW \t\t\t        // Simple expressions don’t need dots\nload1: squants.energy.Power = 100.0 kW\n\nscala\u003e val load2 = 100 megawatts\nload2: squants.energy.Power = 100.0 MW\n\nscala\u003e val time = 3.hours + 45.minutes     // Compound expressions may need dots\ntime: squants.time.Time = 3.75 h\n```\n\nCreate Quantities using operations between other Quantities:\n\n```scala\nscala\u003e val energyUsed = 100.kilowatts * (3.hours + 45.minutes)\nenergyUsed: squants.energy.Energy = 375000.0 Wh\n\nscala\u003e val price = 112.50.USD / 1.megawattHours\nprice: squants.market.Price[squants.energy.Energy] = 112.5 USD/1.0 MWh\n\nscala\u003e val speed = 55.miles / 1.hours\nspeed: squants.motion.Velocity = 24.587249174399997 m/s\n```\n\nCreate Quantities using formatted Strings:\n\n```scala\nscala\u003e val load = Power(\"40 MW\")\nload: scala.util.Try[squants.energy.Power] = Success(40.0 MW)\n```\n\nCreate Quantities using Tuples:\n\n```scala\nscala\u003e val load = Power((40.5, \"MW\"))\nload: scala.util.Try[squants.energy.Power] = Success(40.5 MW)\n```\n\nUse single unit values to simplify expressions:\n\n```scala\nscala\u003e // Hours(1) == 1.hours == hour\n     | val ramp = 100.kilowatts / hour\nramp: squants.energy.PowerRamp = 100000.0 W/h\n\nscala\u003e val speed = 100.kilometers / hour\nspeed: squants.motion.Velocity = 27.77777777777778 m/s\n\nscala\u003e // MegawattHours(1) == 1.megawattHours == megawattHour == MWh\n     | val hi = 100.dollars / MWh\nhi: squants.market.Price[squants.energy.Energy] = 1E+2 USD/1.0 MWh\n\nscala\u003e val low = 40.dollars / megawattHour\nlow: squants.market.Price[squants.energy.Energy] = 4E+1 USD/1.0 MWh\n```\n\nImplicit conversion support for using Doubles, Longs and BigDecimals on the left side of multiply and divide operations:\n\n```scala\nscala\u003e val load = 10.22 * 4.MW\nload: squants.energy.Power = 40.88 MW\n\nscala\u003e val driveArrayCapacity = 12 * 600.gb\ndriveArrayCapacity: squants.information.Information = 7200.0 GB\n\nscala\u003e val freq = 60 / second\nfreq: squants.time.Frequency = 60.0 Hz\n\nscala\u003e val freq2 = BigDecimal(36000000) / hour\nfreq2: squants.time.Frequency = 10000.0 Hz\n```\n\nCreate Quantity Ranges using `to` or `plusOrMinus` (`+-`) operators:\n\n```scala\nval range1 = 1000.kW to 5000.kW\t             // 1000.kW to 5000.kW\nval range2 = 5000.kW plusOrMinus 1000.kW     // 4000.kW to 6000.kW\nval range2 = 5000.kW +- 1000.kW              // 4000.kW to 6000.kW\n```\n\n### Numeric Support\nMost Quantities that support implicit conversions also include an implicit Numeric object that can be imported\nto your code where Numeric support is required.  These follow the following pattern:\n\n```scala\nscala\u003e import squants.mass.{Grams, Kilograms}\nimport squants.mass.{Grams, Kilograms}\n\nscala\u003e import squants.mass.MassConversions.MassNumeric\nimport squants.mass.MassConversions.MassNumeric\n\nscala\u003e val sum = List(Kilograms(100), Grams(34510)).sum\nsum: squants.mass.Mass = 134510.0 g\n```\n\nNOTE - Because a quantity can not be multiplied by a like quantity and return a like quantity, the `Numeric.times`\noperation of numeric is implemented to throw an UnsupportedOperationException for all types except `Dimensionless`.\n\nThe MoneyNumeric implementation is a bit different than the implementations for other quantity types\nin a few important ways.\n\n1. MoneyNumeric is a class, not an object like the others.\n2. To create a MoneyNumeric value there must be an implicit MoneyContext in scope.\n3. The MoneyContext must contain applicable exchange rates if you will be applying cross-currency Numeric ops.\n\nThe following code provides a basic example for creating a MoneyNumeric:\n\n```scala\nimport squants.market.defaultMoneyContext\nimport squants.market.MoneyConversions._\nimport squants.market.USD\nimplicit val moneyContext = defaultMoneyContext\n```\n\n```scala\nscala\u003e implicit val moneyNum = new MoneyNumeric()\nmoneyNum: squants.market.MoneyConversions.MoneyNumeric = MoneyNumeric(MoneyContext(DefaultCurrency(USD),Currencies(ARS,AUD,BRL,BTC,CAD,CHF,CLP,CNY,CZK,DKK,ETH,EUR,GBP,HKD,INR,JPY,KRW,LTC,MXN,MYR,NAD,NOK,NZD,RUB,SEK,USD,XAG,XAU,ZAR),ExchangeRates(),AllowIndirectConversions(true)))\n\nscala\u003e val sum = List(USD(100), USD(10)).sum\nsum: squants.market.Money = 1.1E+2 USD\n```\n\n## Unit groups\n\nSquants provides an experimental API for grouping related `UnitOfMeasure` values together.\nThis are called `UnitGroup`s. Squants provides `UnitGroup` implementations for the SI, the US Customary system, and various other systems. End-users can create their own ad-hoc `UnitGroup`s for `UnitOfMeasure`s in a related dimension.\n\nThe `UnitGroup` trait defines two public fields: `units`, a `Set[UnitOfMeasure]`, and `sortedUnits`, which contains `units` sorted in ascending order.\n\n### SI UnitGroups\n\nAlmost every `Dimension` in Squants has SI Units (with the exception of `Information`\nand `Money`). To avoid boilerplate, Squants generates `UnitGroup`s for SI using implicits.\n\nThere are two `UnitGroup`s provided for SI: \"strict\" and \"expanded.\" Strict only includes SI\nUnitOfMeasure defined in the SI; \"expanded\" includes [non-SI units that are commonly used in](http://www.bipm.org/en/publications/si-brochure/table6.html)\nSI, such as litre, hectare, hour, minute, etc). See the linked document for a detailed list.\n\nTo summon the strict SI `UnitGroup` for `Length`, you would use this code:\n\n```scala\nimport squants.space.Length\n// import squants.space.Length\n\nimport squants.experimental.unitgroups.ImplicitDimensions.space._\n// import squants.experimental.unitgroups.ImplicitDimensions.space._\n\nimport squants.experimental.unitgroups.UnitGroup\n// import squants.experimental.unitgroups.UnitGroup\n\nimport squants.experimental.unitgroups.si.strict.implicits._\n// import squants.experimental.unitgroups.si.strict.implicits._\n\nval siLengths: UnitGroup[Length] = implicitly[UnitGroup[Length]]\n// siLengths: squants.experimental.unitgroups.UnitGroup[squants.space.Length] = squants.experimental.unitgroups.si.strict.package$implicits$$anon$1@f52ca1b\n```\n\nTo print out units and their conversion factors to the primary SI unit, you could use this code:\n\n```scala\nimport squants.{Quantity, UnitOfMeasure}\n// import squants.{Quantity, UnitOfMeasure}\n\ndef mkConversionFactor[A \u003c: Quantity[A]](uom: UnitOfMeasure[A]): Double = {\n  val one = uom(1)\n  one.to(one.dimension.siUnit)\n}\n// mkConversionFactor: [A \u003c: squants.Quantity[A]](uom: squants.UnitOfMeasure[A])Double\n\ndef mkTuple[A \u003c: Quantity[A]](uom: UnitOfMeasure[A]): (String, Double) = {\n  (uom.symbol, mkConversionFactor(uom))\n}\n// mkTuple: [A \u003c: squants.Quantity[A]](uom: squants.UnitOfMeasure[A])(String, Double)\n\nsiLengths.sortedUnits.toList.map(mkTuple).foreach(println)\n// (nm,1.0E-9)\n// (µm,1.0E-6)\n// (mm,0.001)\n// (cm,0.01)\n// (dm,0.1)\n// (m,1.0)\n// (dam,10.0)\n// (hm,100.0)\n// (km,1000.0)\n```\n\nNote that `UnitGroup`'s `sortedUnits` field is a `SortedSet`, so before mapping over it,\nyou will probably want to convert it to a List, otherwise the output may be resorted.\n\n### Non-SI UnitGroups\n\nOther `UnitGroup` definitions don't use implicits. For example, `squants.experimental.unitgroups.uscustomary.space.UsCustomaryLiquidVolumes` or `squants.experimental.unitgroups.misc.TroyMasses` can be imported and used directly.\n\n### Creating an ad-hoc UnitGroup\n\nTo create an ad-hoc `UnitGroup` just implement the trait. For example, to make a US cooking measure `UnitGroup`:\n\n```scala\nimport squants.{Quantity, Dimension}\n// import squants.{Quantity, Dimension}\n\nimport squants.space._\n// import squants.space._\n\nimport squants.experimental.unitgroups.UnitGroup\n// import squants.experimental.unitgroups.UnitGroup\n\nval usCookingUnitGroup = new UnitGroup[Volume] {\n  // units don't have to be specified in-order.\n  val units: Set[UnitOfMeasure[Volume]] = Set(UsPints, UsGallons, Teaspoons, Tablespoons, UsQuarts, FluidOunces)\n}\n// usCookingUnitGroup: squants.experimental.unitgroups.UnitGroup[squants.space.Volume]{val units: Set[squants.UnitOfMeasure[squants.space.Volume]]} = $anon$1@495c28e0\n\n// squants automatically sorts units\nusCookingUnitGroup.sortedUnits.foreach(println)\n// squants.space.Teaspoons$@1f2aa9fd\n// squants.space.Tablespoons$@20a4318e\n// squants.space.FluidOunces$@3f31c22\n// squants.space.UsPints$@6b5332c3\n// squants.space.UsQuarts$@5293da73\n// squants.space.UsGallons$@25de9dee\n```\n\nThe `UnitGroup` values provided with Squants are only samples and aren't intended to be exhaustive.\nWe encourage users to make their own `UnitGroup` defintitions and submit them as PRs if they're generally\napplicable.\n\n## Formatters\n\nSquants provides an experimental API for formatting Quantities in the \"best unit.\" For example,\nconvert Inches(12) to Feet(1). This is useful for producing human-friendly output.\n\nTo use a formatter, you must implement the `squants.formatters.Formatter` trait:\n\n```scala\ntrait Formatter[A \u003c: Quantity[A]] {\n  def inBestUnit(quantity: Quantity[A]): A\n}\n```\n\n### Default Formatter implementation\n\nThere is a default formatter implementation in `squants.experimental.formatter.DefaultFormatter`. This builds on the `UnitGroup`\nAPI discussed above to choose the best `UnitOfMeasure` for a `Quantity`. The `DefaultFormatter` algorithm will probably\nwork for most use-cases, but users can create their own `Formatters` if they have custom needs.\n\nTo use `DefaultFormatter` import it, and a unit group:\n\n```scala\nimport squants.experimental.formatter.DefaultFormatter\nimport squants.experimental.unitgroups.misc.AstronomicalLengthUnitGroup\n```\n\nThen create the formatter by passing in a unit group:\n```scala\nval astroFormatter = new DefaultFormatter(AstronomicalLengthUnitGroup)\n// astroFormatter: squants.experimental.formatter.DefaultFormatter[squants.space.Length] = squants.experimental.formatter.DefaultFormatter@790fe346\n```\n\nNow, we create some values using human-unfriendly numbers:\n\n```scala\nimport squants.space.LengthConversions._\n// import squants.space.LengthConversions._\n\nval earthToJupiter = 588000000.km\n// earthToJupiter: squants.space.Length = 588000000.0 km\n\nval earthToVoyager1 = 2.06e10.km\n// earthToVoyager1: squants.space.Length = 20600000000.0 km\n\nval earthToAlphaCentauri = 4.1315e+13.km\n// earthToAlphaCentauri: squants.space.Length = 41315000000000.0 km\n```\n\nAnd format them into appropriate units (AUs and Parsecs, in this case):\n```scala\nastroFormatter.inBestUnit(earthToJupiter)\n// res3: squants.space.Length = 3.9305372278938457 au\n\nastroFormatter.inBestUnit(earthToVoyager1)\n// res4: squants.space.Length = 137.70249471872998 au\n\nastroFormatter.inBestUnit(earthToAlphaCentauri)\n// res5: squants.space.Length = 1.3389279634339382 pc\n```\n\n\n### Implicit formatters\n\nThere is a nicer syntax for formatters available via implicits.\nThis lets you write expressions such as `12.inches.inBestUnit`. This syntax is added per-`Dimension`.\n\nTo use this syntax, first import `squants.experimental.formatter.syntax._`.\nThen, for each `Dimension` you wish to use, place a Formatter for the Dimension in implicit scope. In this example,\nwe're adding support for `Length`.\n\n```scala\nimport squants.experimental.formatter.DefaultFormatter\nimport squants.experimental.formatter.syntax._\nimport squants.mass.MassConversions._\nimport squants.space.Length\nimport squants.space.LengthConversions._\nimport squants.experimental.unitgroups.misc.AstronomicalLengthUnitGroup\n```\n\n```scala\nimplicit val astroFormatter = new DefaultFormatter(AstronomicalLengthUnitGroup)\n// astroFormatter: squants.experimental.formatter.DefaultFormatter[squants.space.Length] = squants.experimental.formatter.DefaultFormatter@135301a1\n\nval earthToJupiter = 588000000.km\n// earthToJupiter: squants.space.Length = 588000000.0 km\n\nval earthToVoyager1 = 2.06e10.km\n// earthToVoyager1: squants.space.Length = 20600000000.0 km\n\nval earthToAlphaCentauri = 4.1315e+13.km\n// earthToAlphaCentauri: squants.space.Length = 41315000000000.0 km\n\nearthToJupiter.inBestUnit\n// res0: squants.Quantity[squants.space.Length] = 3.9305372278938457 au\n\nearthToVoyager1.inBestUnit\n// res1: squants.Quantity[squants.space.Length] = 137.70249471872998 au\n\nearthToAlphaCentauri.inBestUnit\n// res2: squants.Quantity[squants.space.Length] = 1.3389279634339382 pc\n```\n\nThis example won't compile because there is no `Formatter[Mass]` in implicit scope:\n\n```scala\nscala\u003e 5000.grams.inBestUnit\n\u003cconsole\u003e:26: error: could not find implicit value for parameter formatter: squants.experimental.formatter.Formatter[squants.mass.Mass]\n       5000.grams.inBestUnit\n                  ^\n```\n\n### SI Formatters and implicit syntax\n\nWhen using SI units, and the default formatter algorithm, you don't have to declare a `Formatter` and place it in\nimplicit scope. The compiler can do that for you. This creates a very human-friendly API by using the appropriate\nimports.\n\nFirst, import the SI unit groups and their implicits:\n```scala\nimport squants.experimental.unitgroups.ImplicitDimensions.space._\nimport squants.experimental.unitgroups.si.strict.implicits._\n```\n\nNext, import the formatter syntax described above:\n\n```scala\nimport squants.experimental.formatter.syntax._\n```\n\nFinally, add imports for implicitly deriving formatters:\n```scala\nscala\u003e import squants.experimental.formatter.implicits._\nimport squants.experimental.formatter.implicits._\n```\n\nNow we can create quantities and format them by calling `.inBestUnit` directly:\n\n```scala\nimport squants.space.LengthConversions._\n```\n\n```scala\n5.cm.inBestUnit\n// res0: squants.Quantity[squants.space.Length] = 5.0 cm\n\n500.cm.inBestUnit\n// res1: squants.Quantity[squants.space.Length] = 5.0 m\n\n3000.meters.inBestUnit\n// res2: squants.Quantity[squants.space.Length] = 3.0 km\n```\n\n## Type Hierarchy\nThe type hierarchy includes the following core types:  Quantity, Dimension, and UnitOfMeasure\n\n### Quantity and Dimension\n\nA Dimension represents a type of Quantity. For example: Mass, Length, Time, etc.\n\nA Quantity represents a dimensional value or measurement.  A Quantity is a combination of a numeric value and a unit.\nFor example:  2 lb, 10 km, 3.4 hr.\n\nSquants has built in support for 54 quantity dimensions.\n\n### Unit of Measure\nUnitOfMeasure is the scale or multiplier in which the Quantity is being measured.\nSquants has built in support for over 257 units of measure\n\nFor each Dimension a set of UOM objects implement a primary UOM trait typed to that Quantity.\nThe UOM objects define the unit symbols, conversion factors, and factory methods for creating Quantities in that unit.\n\n### Quantity Implementations\n\nThe code for specific implementations include\n\n* A class representing the Quantity including cross-dimensional operations\n* A companion object representing the Dimension and set of available units\n* A base trait for its Units\n* A set of objects defining specific units, their symbols and conversion factors\n\nThis is an abbreviated example of how a Quantity type is constructed:\n\n```scala\nclass Length(val value: Double, val unit: LengthUnit) extends Quantity[Length]  { ... }\nobject Length extends Dimension[Length]  { ... }\ntrait LengthUnit extends UnitOfMeasure[Length]  { ... }\nobject Meters extends LengthUnit { ... }\nobject Yards extends LengthUnit { ... }\n```\n\nThe apply method of the UOM objects are implemented as factories for creating Quantity values.\n\n```scala\nval len1: Length = Meters(4.3)\nval len2: Length = Yards(5)\n```\n\nSquants currently supports 257 units of measure\n\n### Time Derivatives\n\nSpecial traits are used to establish a time derivative relationship between quantities.\n\nFor example Velocity is the 1st Time Derivative of Length (Distance), Acceleration is the 2nd Time Derivative.\n\n```scala\nclass Length( ... ) extends Quantity[Length] with TimeIntegral[Velocity]\n...\nclass Velocity( ... ) extends Quantity[Velocity] with TimeDerivative[Length] with TimeIntegral[Acceleration]\n...\nclass Acceleration( ... ) extends Quantity[Acceleration] with TimeDerivative[Velocity]\n```\n\nThese traits provide operations with time operands which result in correct dimensional transformations.\n\n\nUsing these imports:\n```scala\nimport squants.energy.Kilowatts\nimport squants.motion.{Acceleration, Velocity}\nimport squants.space.{Kilometers, Length}\nimport squants.space.LengthConversions._\nimport squants.time.{Hours, Seconds, Time}\nimport squants.time.TimeConversions._\n```\n\nYou can code the following:\n```scala\nscala\u003e val distance: Length = Kilometers(100)\ndistance: squants.space.Length = 100.0 km\n\nscala\u003e val time: Time = Hours(2)\ntime: squants.time.Time = 2.0 h\n\nscala\u003e val velocity: Velocity = distance / time\nvelocity: squants.motion.Velocity = 13.88888888888889 m/s\n\nscala\u003e val acc: Acceleration = velocity / Seconds(1)\nacc: squants.motion.Acceleration = 13.88888888888889 m/s²\n\nscala\u003e val gravity = 32.feet / second.squared\ngravity: squants.Acceleration = 9.7536195072 m/s²\n```\n\nPower is the 1st Time Derivative of Energy, PowerRamp is the 2nd.\n```scala\nscala\u003e val power = Kilowatts(100)\npower: squants.energy.Power = 100.0 kW\n\nscala\u003e val time: Time = Hours(2)\ntime: squants.time.Time = 2.0 h\n\nscala\u003e val energy = power * time\nenergy: squants.energy.Energy = 200000.0 Wh\n\nscala\u003e val ramp = Kilowatts(50) / Hours(1)\nramp: squants.energy.PowerRamp = 50000.0 W/h\n```\n\n## Use Cases\n\n### Dimensional Analysis\n\nThe primary use case for Squants, as described above, is to produce code that is typesafe within domains\nthat perform dimensional analysis.\n\nThis code samples in this section use these imports:\n```scala\nimport squants.energy.Energy\nimport squants.energy.EnergyConversions._\nimport squants.energy.PowerConversions._\nimport squants.market.{Money, Price}\nimport squants.market.MoneyConversions._\nimport squants.market.defaultMoneyContext\nimport squants.mass.{Density, Mass}\nimport squants.mass.MassConversions._\nimport squants.motion.{Acceleration, Velocity, VolumeFlow}\nimport squants.motion.AccelerationConversions._\nimport squants.space.LengthConversions._\nimport squants.space.VolumeConversions._\nimport squants.time.Time\nimport squants.time.TimeConversions._\n```\n\n```scala\nscala\u003e implicit val moneyContext = defaultMoneyContext\nmoneyContext: squants.market.MoneyContext = MoneyContext(DefaultCurrency(USD),Currencies(ARS,AUD,BRL,BTC,CAD,CHF,CLP,CNY,CZK,DKK,ETH,EUR,GBP,HKD,INR,JPY,KRW,LTC,MXN,MYR,NAD,NOK,NZD,RUB,SEK,USD,XAG,XAU,ZAR),ExchangeRates(),AllowIndirectConversions(true))\n\nscala\u003e val energyPrice: Price[Energy] = 45.25.money / megawattHour\nenergyPrice: squants.market.Price[squants.energy.Energy] = 45.25 USD/1.0 MWh\n\nscala\u003e val energyUsage: Energy = 345.kilowatts * 5.4.hours\nenergyUsage: squants.energy.Energy = 1863000.0000000002 Wh\n\nscala\u003e val energyCost: Money = energyPrice * energyUsage\nenergyCost: squants.market.Money = 84.30075000000000905 USD\n\nscala\u003e val dodgeViper: Acceleration = 60.miles / hour / 3.9.seconds\ndodgeViper: squants.motion.Acceleration = 6.877552216615386 m/s²\n\nscala\u003e val speedAfter5Seconds: Velocity = dodgeViper * 5.seconds\nspeedAfter5Seconds: squants.motion.Velocity = 34.38776108307693 m/s\n\nscala\u003e val timeTo100MPH: Time = 100.miles / hour / dodgeViper\ntimeTo100MPH: squants.time.Time = 6.499999999999999 s\n\nscala\u003e val density: Density = 1200.kilograms / cubicMeter\ndensity: squants.mass.Density = 1200.0 kg/m³\n\nscala\u003e val volFlowRate: VolumeFlow = 10.gallons / minute\nvolFlowRate: squants.motion.VolumeFlow = 6.30901964E-4 m³/s\n\nscala\u003e val flowTime: Time = 30.minutes\nflowTime: squants.time.Time = 30.0 m\n\nscala\u003e val totalMassFlow: Mass = volFlowRate * flowTime * density\ntotalMassFlow: squants.mass.Mass = 1362.7482422399999 kg\n```\n\n### Domain Modeling\nAnother excellent use case for Squants is stronger typing for fields in your domain model.\n\nCode samples in this section use these imports:\n```scala\nimport scala.language.postfixOps\n\nimport squants.energy.{Energy, Power, PowerRamp}\nimport squants.energy.EnergyConversions._\nimport squants.energy.PowerConversions._\nimport squants.energy.PowerRampConversions._\nimport squants.market.Price\nimport squants.market.MoneyConversions._\nimport squants.time.Time\nimport squants.time.TimeConversions._\n```\n\nThis is OK ...\n\n```scala\ncase class Generator(\n  id: String,\n  maxLoadKW: Double,\n  rampRateKWph: Double,\n  operatingCostPerMWh: Double,\n  currency: String,\n  maintenanceTimeHours: Double)\n\nval gen1 = Generator(\"Gen1\", 5000, 7500, 75.4, \"USD\", 1.5)\nval gen2 = Generator(\"Gen2\", 100, 250, 2944.5, \"JPY\", 0.5)\n```\n\n... but this is much better\n\n```scala\ncase class Generator(\n  id: String,\n  maxLoad: Power,\n  rampRate: PowerRamp,\n  operatingCost: Price[Energy],\n  maintenanceTime: Time)\n\nval gen1 = Generator(\"Gen1\", 5 MW, 7.5.MW/hour, 75.4.USD/MWh, 1.5 hours)\nval gen2 = Generator(\"Gen2\", 100 kW, 250 kWph, 2944.5.JPY/MWh, 30 minutes)\n```\n\n### Anticorruption Layers\n\nCreate wrappers around external services that use basic types to represent quantities.\nYour application code then uses the ACL to communicate with that system thus eliminating the need to deal\nwith type and scale conversions in multiple places throughout your application logic.\n\n```scala\nclass ScadaServiceAnticorruption(val service: ScadaService) {\n  // ScadaService returns meter load as Double representing Megawatts\n  def getLoad: Power = Megawatts(service.getLoad(meterId))\n  }\n  // ScadaService.sendTempBias requires a Double representing Fahrenheit\n  def sendTempBias(temp: Temperature) =\n    service.sendTempBias(temp.to(Fahrenheit))\n}\n```\n\nImplement the ACL as a trait and mix in to the application's services where needed.\n\n```scala\nimport squants.radio.{Irradiance, WattsPerSquareMeter}\nimport squants.thermal.{Celsius, Temperature}\n\ntrait WeatherServiceAntiCorruption {\n  val service: WeatherService\n  def getTemperature: Temperature = Celsius(service.getTemperature)\n  def getIrradiance: Irradiance = WattsPerSquareMeter(service.getIrradiance)\n}\n```\n\nExtend the pattern to provide multi-currency support\n\n```scala\nclass MarketServiceAnticorruption(val service: MarketService)\n     (implicit val moneyContext: = MoneyContext) {\n\n  // MarketService.getPrice returns a Double representing $/MegawattHour\n  def getPrice: Price[Energy] =\n    (USD(service.getPrice) in moneyContext.defaultCurrency) / megawattHour\n\n  // MarketService.sendBid requires a Double representing $/MegawattHour\n  // and another Double representing the max amount of energy in MegawattHours\n  def sendBid(bid: Price[Energy], limit: Energy) =\n    service.sendBid((bid * megawattHour) to USD, limit to MegawattHours)\n}\n```\n\nBuild Anticorruption into Akka routers\n\n```scala\n// LoadReading message used within a Squants enabled application context\ncase class LoadReading(meterId: String, time: Long, load: Power)\nclass ScadaLoadListener(router: Router) extends Actor {\n  def receive = {\n   // ScadaLoadReading - from an external service - sends load as a string\n   // eg, “10.3 MW”, “345 kW”\n   case msg @ ScadaLoadReading(meterId, time, loadString) ⇒\n    // Parse the string and on success emit the Squants enabled event to routees\n    Power(loadString) match {\n      case Success(p) =\u003e router.route(LoadReading(meterId, time, p), sender())\n      case Failure(e) =\u003e // react to QuantityStringParseException\n    }\n  }\n}\n```\n\n... and REST API's with contracts that require basic types\n\n```scala\ntrait LoadRoute extends HttpService {\n  def repo: LoadRepository\n  val loadRoute = {\n    path(\"meter-reading\") {\n      // REST API contract requires load value and units in different fields\n      // Units are string values that may be 'kW' or 'MW'\n      post {\n        parameters(meterId, time, loadDouble, unit) { (meterId, time, loadDouble, unit) =\u003e\n          complete {\n            val load = unit match {\n              case \"kW\" =\u003e Kilowatts(loadDouble)\n              case \"MW\" =\u003e Megawatts(loadDouble)\n            }\n            repo.saveLoad(meterId, time, load)\n          }\n        }\n      } ~\n      // REST API contract requires load returned as a number representing megawatts\n      get {\n        parameters(meterId, time) { (meterId, time) =\u003e\n          complete {\n            repo.getLoad(meterId, time) to Megawatts\n          }\n        }\n      }\n    }\n  }\n}\n```\n\n## Contributors\n\n* Gary Keorkunian ([garyKeorkunian](https://github.com/garyKeorkunian))\n* Jeremy Apthorp ([nornagon](https://github.com/nornagon))\n* Steve Barham ([stevebarham](https://github.com/stevebarham))\n* Derek Morr ([derekmorr](https://github.com/derekmorr))\n* Michael Korbakov ([rmihael](https://github.com/rmihael))\n* Florian Nussberger ([fnussber](https://github.com/fnussber))\n* Ajay Chandran ([ajaychandran](https://github.com/ajaychandran))\n* Gia Bảo ([giabao](https://github.com/giabao))\n* Josh Lemer ([joshlemer](https://github.com/joshlemer))\n* Dave DeCarpio ([DaveDeCaprio](https://github.com/DaveDeCaprio))\n* Carlos Quiroz ([cquiroz](https://github.com/cquiroz))\n* Szabolcs Berecz ([khernyo](https://github.com/khernyo))\n* Matt Hicks ([darkfrog26](https://github.com/darkfrog26))\n* golem131 ([golem131](https://github.com/golem131))\n* Ian O'Hara ([ianohara](https://github.com/ianohara))\n* Shadaj Laddad ([shadaj](https://github.com/shadaj))\n* Ian McIntosh ([cranst0n](https://github.com/cranst0n))\n* Doug Hurst ([robotsnowfall](https://github.com/robotsnowfall))\n* Philip Axelrod ([Paxelord](https://github.com/paxelord))\n\n## Code of Conduct\n\nSquants is a [Typelevel](http://typelevel.org/) Incubator Project and, as such, supports the [Typelevel Code of Conduct](http://typelevel.org/conduct).\n\n## Caveats\n\nCode is offered as-is, with no implied warranty of any kind.\nComments, criticisms, and/or praise are welcome, especially from scientists, engineers and the like.\n\n# Release procedure\n\nMaking a release requires permission to publish to sonatype, and a properly setup [signing key](http://www.scala-sbt.org/sbt-pgp/usage.html):\n\nTo make a release do the following:\n\n* Ensure the version is not set to `SNAPSHOT`\n\n* Build the README using tut\n\n```\n  sbt tut\n```\n\n* Publish a cross-version signed package (no cross-version available for Scala Native)\n```\n  sbt +squantsJVM/publishSigned\n  sbt +squantsJS/publishSigned\n  sbt squantsNative/publishSigned\n```\n\n* Repeat for scala.js 1.0.0-RC1\n```\n  SCALAJS_VERSION=1.0.0-RC1 sbt +squantsJS/publishSigned\n```\n\n* Then make a release (Note: after this step the release cannot be replaced)\n```\n  sbt sonatypeRelease\n```\n","funding_links":[],"categories":["Table of Contents","Functional Programming"],"sub_categories":["Science and Data Analysis"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftypelevel%2Fsquants","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftypelevel%2Fsquants","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftypelevel%2Fsquants/lists"}