{"id":16833528,"url":"https://github.com/ole/ampere","last_synced_at":"2025-07-13T00:40:10.441Z","repository":{"id":56646014,"uuid":"64555429","full_name":"ole/Ampere","owner":"ole","description":"Adding multiplication and division to the units of measurement types in Foundation.","archived":false,"fork":false,"pushed_at":"2021-05-03T10:30:19.000Z","size":73,"stargazers_count":172,"open_issues_count":4,"forks_count":17,"subscribers_count":8,"default_branch":"main","last_synced_at":"2025-04-02T03:34:47.097Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://oleb.net/blog/2016/07/unitproduct/","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ole.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-07-30T17:14:26.000Z","updated_at":"2025-02-26T17:35:52.000Z","dependencies_parsed_at":"2022-08-15T22:31:30.738Z","dependency_job_id":null,"html_url":"https://github.com/ole/Ampere","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/ole/Ampere","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ole%2FAmpere","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ole%2FAmpere/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ole%2FAmpere/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ole%2FAmpere/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ole","download_url":"https://codeload.github.com/ole/Ampere/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ole%2FAmpere/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":265076118,"owners_count":23707513,"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-10-13T11:54:32.061Z","updated_at":"2025-07-13T00:40:10.389Z","avatar_url":"https://github.com/ole.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Ampere\n\nBy [Ole Begemann](https://oleb.net/), July 2016\n\nA Swift library that extends Foundation’s units and measurements APIs with type-safe multiplication and division.\n\n\n## Requirements\n\nSwift 5.0 or higher.\n\nAmpere should work both on Apple OSes and on other platforms where Swift is available (Linux, Windows).\n\n![](https://github.com/ole/Ampere/workflows/macOS/badge.svg) ![](https://github.com/ole/Ampere/workflows/Linux/badge.svg)\n\n\n## Dependencies\n\n* Foundation\n* On Apple platforms, the minimum deployment targets are (I believe):\n  - iOS 10\n  - macOS 10.12\n  - tvOS 10\n  - watchOS 3\n\n\n## Usage\n\nThe library is a [Swift Package Manager](https://swift.org/package-manager/) package. Add this line to your `Package.swift` file to add Ampere as a dependency:\n\n~~~swift\nlet package = Package(\n    ...\n    dependencies: [\n        .package(url: \"https://github.com/ole/Ampere.git\", from: \"0.4.0\"),\n    ],\n    ...\n~~~\n\n\nIn your code, import Ampere like so:\n\n~~~swift\nimport Ampere\n~~~\n\nas an Xcode project that builds an iOS Framework target. I have not (yet) set it up for CocoaPods, Carthage, or the Swift Package Manager. (Although I assume Carthage should build it out of the box.)\n\nClone the repository, open the project in Xcode, and check out the tests. If you want to use this in your own project in the current form, drag and drop the project file into your Xcode project and add the framework to your linked libraries, or copy the files directly into your project.\n\n\n## Examples\n\nTo compute a velocity, we can divide length by time, i.e. `Measurement\u003cUnitLength\u003e / Measurement\u003cUnitDuration\u003e`:\n\n~~~swift\nimport Ampere\n\nlet length = Measurement(value: 100, unit: UnitLength.meters)\nlet time = Measurement(value: 10, unit: UnitDuration.seconds)\nlet speed = length / time\n// → 10.0 m/s 🎉\n~~~\n\nTo compute energy, multiply power by time, i.e. `Measurement\u003cUnitPower\u003e * Measurement\u003cUnitDuration\u003e`:\n\n~~~swift\nimport Ampere\n\nlet power = Measurement(value: 20, unit: UnitPower.kilowatts)\nlet time = Measurement(value: 3, unit: UnitDuration.hours)\nlet energy: Measurement\u003cUnitEnergy\u003e = power * time\n// → 216000000.0 J\nenergy.converted(to: .kilowattHours)\n// → 60.0 kWh\n~~~\n\nNotice that in this case we had to explicitly specify the type of the `energy` variable in `let energy: Measurement\u003cUnitEnergy\u003e`. Sometimes the compiler cannot infer the correct type automatically and we have to help it.\n\n\n## Additional Units\n\nThis library defines the following custom units because they are not included in Foundation:\n\n- `UnitForce`, measured in newtons. The base unit is `.newtons`.\n\n\n## Implemented Relations\n\nThis library currently defines the following relations:\n\n| Relation                       | Example               |\n| -------------                  | -------------         |\n| area = length × length         | 1 m² = 1 m × 1 m      |\n| volume = area × length         | 1 m³ = 1 m² × 1 m     |\n| density = mass / volume        | 1 kg/m³ = 1 kg / 1 m³ | \n| velocity = length / time       | 1 m/s = 1 m / 1 s     |\n| acceleration = velocity / time | 1 m/s² = 1 m/s / 1 s  |\n| energy = power × time          | 1 J = 1 W × 1 s       |\n| resistance = voltage / current | 1 Ω = 1 V / 1 A       |\n| charge = current × time        | 1 C = 1 A × 1 s       |\n| force = mass × acceleration    | 1 N = 1 kg × 1 m/s²   |\n\n\n## Adding Relations\n\nMissing something? Pull requests welcome! It’s very easy to add additional relations. All you have to do is to conform your desired type to the `UnitProduct` protocol, like so:\n\n~~~swift\n/// Energy = Power * Duration\n/// 1 J = 1 W * 1 s\nextension UnitEnergy: UnitProduct {\n    public typealias Factor1 = UnitPower\n    public typealias Factor2 = UnitDuration\n    public typealias Product = UnitEnergy\n\n    public static func defaultUnitMapping() -\u003e (Factor1, Factor2, Product) {\n        return (.watts, .seconds, .joules)\n    }\n}\n~~~\n\nThis says that the conforming type `UnitEnergy` is the product of the two associated types `Factor1` (`UnitPower`) and `Factor2` (`UnitDuration`).\n\nThe `defaultUnitMapping` method defines the units for the three types that should be used for computations. By returning `(.watts, .seconds, .joules)`, we say that _1 W × 1 s = 1 J_. These must be consistent so that the resulting equation is valid. We could just as well have returned `(.kilowatts, .hours, .kilowattHours)`, but something like `(.watts, .hours, .joules)` would produce wrong results.\n\nNote that Ampere expresses all relations as _products_, i.e. multiplications. If you want to express a ratio, such as _speed = length / time_, you first have to rearrange the equation into a multiplication, i.e. _length = speed × time_. This is why this particular relation is defined on `UnitLength` and not `UnitSpeed`. A separate protocol for ratios of units should not be necessary because every ratio can be transformed into an equivalent product equation.\n\nFor units that are the _square_ of another units, i.e. where both factors of the product are the same type, use the `UnitSquare` protocol. An existing example of this is `UnitArea`, which is `UnitLength * UnitLength`.\n\n\n## Limitations\n\nCurrently [some relations cannot be expressed](https://github.com/ole/Ampere/issues/5) due to conflicts with other definitions. As an example, consider the relation _pressure = force / area_. In Ampere, we would express this in terms of _force = pressure × area_ because all relations are expressed as multiplications (see above).\n\nHowever, _force = pressure × area_ conflicts with the existing _force = mass × acceleration_ — `UnitForce` can only conform once to `UnitProduct` so we cannot express both of these. It could be that the only solution is to introduce a separate `UnitRatio` protocol after all, but that’s not implemented yet.\n\n\n## More Information\n\nI wrote a series of blog posts about this: [Part 1], [Part 2], [Part 3]. Part 2 in particular explains the implementation in a lot of detail.\n\n\n## License\n\nMIT License. See LICENSE.txt file for details.\n\n[Part 1]: https://oleb.net/blog/2016/07/measurements-and-units/\n[Part 2]: https://oleb.net/blog/2016/07/unitproduct/\n[Part 3]: https://oleb.net/blog/2016/07/unitsquare/\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fole%2Fampere","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fole%2Fampere","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fole%2Fampere/lists"}