ucon 0.4.0__tar.gz → 0.4.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {ucon-0.4.0 → ucon-0.4.1}/PKG-INFO +2 -2
- {ucon-0.4.0 → ucon-0.4.1}/ROADMAP.md +2 -2
- ucon-0.4.1/docs/explainers/exponent-scale-relationship.md +347 -0
- {ucon-0.4.0 → ucon-0.4.1}/setup.py +1 -1
- ucon-0.4.1/tests/ucon/conversion/test_graph.py +409 -0
- ucon-0.4.1/tests/ucon/conversion/test_map.py +409 -0
- {ucon-0.4.0 → ucon-0.4.1}/tests/ucon/test_core.py +5 -6
- ucon-0.4.1/tests/ucon/test_default_graph_conversions.py +443 -0
- {ucon-0.4.0 → ucon-0.4.1}/tests/ucon/test_quantity.py +43 -49
- {ucon-0.4.0 → ucon-0.4.1}/ucon/graph.py +8 -0
- {ucon-0.4.0 → ucon-0.4.1}/ucon/units.py +5 -0
- {ucon-0.4.0 → ucon-0.4.1}/ucon.egg-info/PKG-INFO +2 -2
- {ucon-0.4.0 → ucon-0.4.1}/ucon.egg-info/SOURCES.txt +2 -0
- ucon-0.4.0/tests/ucon/conversion/test_graph.py +0 -175
- ucon-0.4.0/tests/ucon/conversion/test_map.py +0 -163
- {ucon-0.4.0 → ucon-0.4.1}/.github/workflows/publish.yaml +0 -0
- {ucon-0.4.0 → ucon-0.4.1}/.github/workflows/tests.yaml +0 -0
- {ucon-0.4.0 → ucon-0.4.1}/.gitignore +0 -0
- {ucon-0.4.0 → ucon-0.4.1}/LICENSE +0 -0
- {ucon-0.4.0 → ucon-0.4.1}/NOTICE +0 -0
- {ucon-0.4.0 → ucon-0.4.1}/README.md +0 -0
- {ucon-0.4.0 → ucon-0.4.1}/docs/decisions/composable-unit-algebra.md +0 -0
- {ucon-0.4.0 → ucon-0.4.1}/docs/decisions/composite-units.md +0 -0
- {ucon-0.4.0 → ucon-0.4.1}/docs/decisions/unit-algebra-naming.md +0 -0
- {ucon-0.4.0 → ucon-0.4.1}/docs/decisions/unity-distance-metric-for-nearest-scale.md +0 -0
- {ucon-0.4.0 → ucon-0.4.1}/docs/explainers/type-operation-matrix.md +0 -0
- {ucon-0.4.0 → ucon-0.4.1}/docs/explainers/why-algebraic-closure-matters.md +0 -0
- {ucon-0.4.0 → ucon-0.4.1}/docs/explainers/why-type-safety-matters.md +0 -0
- {ucon-0.4.0 → ucon-0.4.1}/docs/proposals/interface-unifying-the-value-layer.md +0 -0
- {ucon-0.4.0 → ucon-0.4.1}/docs/proposals/project_unified-algebraic-core.md +0 -0
- {ucon-0.4.0 → ucon-0.4.1}/docs/proposals/support-for-fractional-exponents.md +0 -0
- {ucon-0.4.0 → ucon-0.4.1}/docs/proposals/unified-unit-presentation.md +0 -0
- {ucon-0.4.0 → ucon-0.4.1}/noxfile.py +0 -0
- {ucon-0.4.0 → ucon-0.4.1}/requirements.txt +0 -0
- {ucon-0.4.0 → ucon-0.4.1}/setup.cfg +0 -0
- {ucon-0.4.0 → ucon-0.4.1}/tests/__init__.py +0 -0
- {ucon-0.4.0 → ucon-0.4.1}/tests/ucon/__init__.py +0 -0
- {ucon-0.4.0 → ucon-0.4.1}/tests/ucon/conversion/__init__.py +0 -0
- {ucon-0.4.0 → ucon-0.4.1}/tests/ucon/test_algebra.py +0 -0
- {ucon-0.4.0 → ucon-0.4.1}/tests/ucon/test_units.py +0 -0
- {ucon-0.4.0 → ucon-0.4.1}/ucon/__init__.py +0 -0
- {ucon-0.4.0 → ucon-0.4.1}/ucon/algebra.py +0 -0
- {ucon-0.4.0 → ucon-0.4.1}/ucon/core.py +0 -0
- {ucon-0.4.0 → ucon-0.4.1}/ucon/maps.py +0 -0
- {ucon-0.4.0 → ucon-0.4.1}/ucon/quantity.py +0 -0
- {ucon-0.4.0 → ucon-0.4.1}/ucon.egg-info/dependency_links.txt +0 -0
- {ucon-0.4.0 → ucon-0.4.1}/ucon.egg-info/top_level.txt +0 -0
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ucon
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.1
|
|
4
4
|
Summary: a tool for dimensional analysis: a "Unit CONverter"
|
|
5
5
|
Home-page: https://github.com/withtwoemms/ucon
|
|
6
6
|
Author: Emmanuel I. Obi
|
|
7
7
|
Maintainer: Emmanuel I. Obi
|
|
8
8
|
Maintainer-email: withtwoemms@gmail.com
|
|
9
9
|
License: Apache-2.0
|
|
10
|
-
Classifier: Development Status ::
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
11
|
Classifier: Intended Audience :: Developers
|
|
12
12
|
Classifier: Intended Audience :: Education
|
|
13
13
|
Classifier: Intended Audience :: Science/Research
|
|
@@ -69,8 +69,8 @@ Building on v0.3.5 baseline:
|
|
|
69
69
|
- [x] `Dimension.information` with `units.bit` and `units.byte`
|
|
70
70
|
- [x] `Vector` extended to 8 components (added B for information)
|
|
71
71
|
- [x] Information unit conversions in default graph (byte ↔ bit)
|
|
72
|
-
- [
|
|
73
|
-
- [
|
|
72
|
+
- [x] Extend tests to include temperature, pressure, and base SI conversions
|
|
73
|
+
- [x] Document Exponent/Scale relationship in developer guide
|
|
74
74
|
|
|
75
75
|
### 🧩 Outcomes
|
|
76
76
|
- Unified conversion taxonomy
|
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
# Developer Guide: Exponent and Scale Relationship
|
|
2
|
+
|
|
3
|
+
> Understanding the algebraic foundation of magnitude prefixes in ucon.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Overview
|
|
8
|
+
|
|
9
|
+
The `Exponent` and `Scale` classes form the algebraic foundation for handling magnitude prefixes (kilo, milli, mebi, etc.) in ucon. This guide explains their relationship and how they work together.
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
13
|
+
│ Scale (Enum) │
|
|
14
|
+
│ kilo, milli, mega, kibi, mebi, etc. │
|
|
15
|
+
│ │ │
|
|
16
|
+
│ ▼ │
|
|
17
|
+
│ ScaleDescriptor (dataclass) │
|
|
18
|
+
│ shorthand: "k", alias: "kilo" │
|
|
19
|
+
│ │ │
|
|
20
|
+
│ ▼ │
|
|
21
|
+
│ Exponent (class) │
|
|
22
|
+
│ base: 10, power: 3 │
|
|
23
|
+
│ evaluated: 1000.0 │
|
|
24
|
+
└─────────────────────────────────────────────────────────────┘
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Exponent: The Algebraic Primitive
|
|
30
|
+
|
|
31
|
+
`Exponent` (`ucon.algebra`) represents a base-power pair like 10³ or 2¹⁰.
|
|
32
|
+
|
|
33
|
+
### Structure
|
|
34
|
+
|
|
35
|
+
```python
|
|
36
|
+
class Exponent:
|
|
37
|
+
base: int # 2 or 10 only
|
|
38
|
+
power: int | float
|
|
39
|
+
|
|
40
|
+
@property
|
|
41
|
+
def evaluated(self) -> float:
|
|
42
|
+
return self.base ** self.power
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Supported Bases
|
|
46
|
+
|
|
47
|
+
Only two bases are supported, chosen for their prevalence in scientific and computing contexts:
|
|
48
|
+
|
|
49
|
+
| Base | Use Case | Examples |
|
|
50
|
+
|------|----------|----------|
|
|
51
|
+
| **10** | SI prefixes (metric) | kilo (10³), milli (10⁻³), mega (10⁶) |
|
|
52
|
+
| **2** | Binary prefixes (IEC) | kibi (2¹⁰), mebi (2²⁰), gibi (2³⁰) |
|
|
53
|
+
|
|
54
|
+
### Arithmetic Operations
|
|
55
|
+
|
|
56
|
+
Exponent supports algebraic operations that mirror the rules of exponents:
|
|
57
|
+
|
|
58
|
+
```python
|
|
59
|
+
from ucon.algebra import Exponent
|
|
60
|
+
|
|
61
|
+
kilo = Exponent(10, 3) # 10³ = 1000
|
|
62
|
+
milli = Exponent(10, -3) # 10⁻³ = 0.001
|
|
63
|
+
|
|
64
|
+
# Multiplication: add powers (same base)
|
|
65
|
+
kilo * milli # → Exponent(10, 0) = 1
|
|
66
|
+
|
|
67
|
+
# Division: subtract powers (same base)
|
|
68
|
+
kilo / milli # → Exponent(10, 6) = 1,000,000
|
|
69
|
+
|
|
70
|
+
# Exponentiation: multiply power
|
|
71
|
+
kilo ** 2 # → Exponent(10, 6) = 1,000,000
|
|
72
|
+
|
|
73
|
+
# Cross-base operations return float
|
|
74
|
+
kibi = Exponent(2, 10) # 2¹⁰ = 1024
|
|
75
|
+
kilo / kibi # → 0.9765625 (float, not Exponent)
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Base Conversion
|
|
79
|
+
|
|
80
|
+
Convert between bases while preserving numeric value:
|
|
81
|
+
|
|
82
|
+
```python
|
|
83
|
+
kibi = Exponent(2, 10) # 1024
|
|
84
|
+
kibi.to_base(10) # → Exponent(10, 3.0103...) ≈ 1024
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## ScaleDescriptor: Adding Human-Readable Labels
|
|
90
|
+
|
|
91
|
+
`ScaleDescriptor` (`ucon.core`) wraps an `Exponent` with display information:
|
|
92
|
+
|
|
93
|
+
```python
|
|
94
|
+
@dataclass(frozen=True)
|
|
95
|
+
class ScaleDescriptor:
|
|
96
|
+
exponent: Exponent
|
|
97
|
+
shorthand: str # "k", "M", "Ki"
|
|
98
|
+
alias: str # "kilo", "mega", "kibi"
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Properties
|
|
102
|
+
|
|
103
|
+
```python
|
|
104
|
+
desc = ScaleDescriptor(Exponent(10, 3), "k", "kilo")
|
|
105
|
+
|
|
106
|
+
desc.evaluated # 1000.0 (delegates to exponent)
|
|
107
|
+
desc.base # 10
|
|
108
|
+
desc.power # 3
|
|
109
|
+
desc.parts() # (10, 3)
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## Scale: The User-Facing Enum
|
|
115
|
+
|
|
116
|
+
`Scale` (`ucon.core`) is an enum where each member's value is a `ScaleDescriptor`.
|
|
117
|
+
|
|
118
|
+
### Available Scales
|
|
119
|
+
|
|
120
|
+
```python
|
|
121
|
+
class Scale(Enum):
|
|
122
|
+
# Binary (base 2)
|
|
123
|
+
gibi = ScaleDescriptor(Exponent(2, 30), "Gi", "gibi") # 2³⁰
|
|
124
|
+
mebi = ScaleDescriptor(Exponent(2, 20), "Mi", "mebi") # 2²⁰
|
|
125
|
+
kibi = ScaleDescriptor(Exponent(2, 10), "Ki", "kibi") # 2¹⁰
|
|
126
|
+
|
|
127
|
+
# Decimal (base 10)
|
|
128
|
+
peta = ScaleDescriptor(Exponent(10, 15), "P", "peta")
|
|
129
|
+
tera = ScaleDescriptor(Exponent(10, 12), "T", "tera")
|
|
130
|
+
giga = ScaleDescriptor(Exponent(10, 9), "G", "giga")
|
|
131
|
+
mega = ScaleDescriptor(Exponent(10, 6), "M", "mega")
|
|
132
|
+
kilo = ScaleDescriptor(Exponent(10, 3), "k", "kilo")
|
|
133
|
+
hecto = ScaleDescriptor(Exponent(10, 2), "h", "hecto")
|
|
134
|
+
deca = ScaleDescriptor(Exponent(10, 1), "da", "deca")
|
|
135
|
+
one = ScaleDescriptor(Exponent(10, 0), "", "") # identity
|
|
136
|
+
deci = ScaleDescriptor(Exponent(10, -1), "d", "deci")
|
|
137
|
+
centi = ScaleDescriptor(Exponent(10, -2), "c", "centi")
|
|
138
|
+
milli = ScaleDescriptor(Exponent(10, -3), "m", "milli")
|
|
139
|
+
micro = ScaleDescriptor(Exponent(10, -6), "µ", "micro")
|
|
140
|
+
nano = ScaleDescriptor(Exponent(10, -9), "n", "nano")
|
|
141
|
+
pico = ScaleDescriptor(Exponent(10, -12),"p", "pico")
|
|
142
|
+
femto = ScaleDescriptor(Exponent(10, -15),"f", "femto")
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### Scale Arithmetic
|
|
146
|
+
|
|
147
|
+
Scale operations delegate to Exponent arithmetic, then resolve back to a Scale:
|
|
148
|
+
|
|
149
|
+
```python
|
|
150
|
+
from ucon.core import Scale
|
|
151
|
+
|
|
152
|
+
# Multiplication
|
|
153
|
+
Scale.kilo * Scale.kilo # → Scale.mega (10³ × 10³ = 10⁶)
|
|
154
|
+
Scale.kilo * Scale.milli # → Scale.one (10³ × 10⁻³ = 10⁰)
|
|
155
|
+
|
|
156
|
+
# Division
|
|
157
|
+
Scale.mega / Scale.kilo # → Scale.kilo (10⁶ / 10³ = 10³)
|
|
158
|
+
Scale.kilo / Scale.mega # → Scale.milli (10³ / 10⁶ = 10⁻³)
|
|
159
|
+
|
|
160
|
+
# Exponentiation
|
|
161
|
+
Scale.kilo ** 2 # → Scale.mega (10³)² = 10⁶
|
|
162
|
+
Scale.milli ** -1 # → Scale.kilo (10⁻³)⁻¹ = 10³
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### Nearest Scale Resolution
|
|
166
|
+
|
|
167
|
+
When arithmetic produces a non-standard power, `Scale.nearest()` finds the closest match:
|
|
168
|
+
|
|
169
|
+
```python
|
|
170
|
+
# Non-exact result resolves to nearest scale
|
|
171
|
+
Scale.kilo * Scale.kibi # Cross-base: 1000 × 1024 = 1,024,000
|
|
172
|
+
# → resolves to Scale.mega (closest)
|
|
173
|
+
|
|
174
|
+
# Manual nearest lookup
|
|
175
|
+
Scale.nearest(5000) # → Scale.kilo (10³ = 1000 is closest)
|
|
176
|
+
Scale.nearest(500) # → Scale.one (undershoot bias)
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
The `undershoot_bias` parameter (default 0.75) penalizes scales smaller than the value, preferring slight overestimation for cleaner display.
|
|
180
|
+
|
|
181
|
+
### Scale × Unit → UnitProduct
|
|
182
|
+
|
|
183
|
+
The primary use case: applying a scale to a unit:
|
|
184
|
+
|
|
185
|
+
```python
|
|
186
|
+
from ucon.core import Scale
|
|
187
|
+
from ucon import units
|
|
188
|
+
|
|
189
|
+
km = Scale.kilo * units.meter # → UnitProduct with kilo-scaled meter
|
|
190
|
+
mg = Scale.milli * units.gram # → UnitProduct with milli-scaled gram
|
|
191
|
+
|
|
192
|
+
print(km.shorthand) # "km"
|
|
193
|
+
print(mg.shorthand) # "mg"
|
|
194
|
+
|
|
195
|
+
# Used in Number construction
|
|
196
|
+
distance = km(5) # 5 kilometers
|
|
197
|
+
mass = mg(250) # 250 milligrams
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
---
|
|
201
|
+
|
|
202
|
+
## The Complete Stack
|
|
203
|
+
|
|
204
|
+
Here's how it all fits together:
|
|
205
|
+
|
|
206
|
+
```
|
|
207
|
+
User writes: km = Scale.kilo * units.meter
|
|
208
|
+
│
|
|
209
|
+
▼
|
|
210
|
+
Scale.kilo ScaleDescriptor(Exponent(10, 3), "k", "kilo")
|
|
211
|
+
│
|
|
212
|
+
▼
|
|
213
|
+
Scale.__mul__(Unit) Returns UnitProduct({UnitFactor(meter, kilo): 1})
|
|
214
|
+
│
|
|
215
|
+
▼
|
|
216
|
+
UnitProduct Stores the unit with its scale prefix
|
|
217
|
+
│
|
|
218
|
+
▼
|
|
219
|
+
Number(5, unit=km) <5 km> with quantity=5, preserving "kilo" scale
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
---
|
|
223
|
+
|
|
224
|
+
## Key Design Decisions
|
|
225
|
+
|
|
226
|
+
### Why Separate Exponent from Scale?
|
|
227
|
+
|
|
228
|
+
1. **Algebraic Closure**: Exponent handles the pure math of base-power pairs without display concerns
|
|
229
|
+
2. **Cross-Base Operations**: 2¹⁰ / 10³ returns a float because no single base can represent it
|
|
230
|
+
3. **Nearest Resolution**: Scale can find the "closest" human-readable prefix for arbitrary values
|
|
231
|
+
|
|
232
|
+
### Why Only Base 2 and 10?
|
|
233
|
+
|
|
234
|
+
These are the only bases with standardized prefix names:
|
|
235
|
+
- **Base 10**: SI prefixes (kilo, mega, giga, etc.)
|
|
236
|
+
- **Base 2**: IEC binary prefixes (kibi, mebi, gibi, etc.)
|
|
237
|
+
|
|
238
|
+
Other bases would require inventing new prefix names.
|
|
239
|
+
|
|
240
|
+
### Why ScaleDescriptor?
|
|
241
|
+
|
|
242
|
+
Separates concerns:
|
|
243
|
+
- `Exponent`: Pure numeric computation
|
|
244
|
+
- `ScaleDescriptor`: Adds shorthand ("k") and alias ("kilo") for display
|
|
245
|
+
- `Scale`: Enum providing named access and class methods like `nearest()`
|
|
246
|
+
|
|
247
|
+
---
|
|
248
|
+
|
|
249
|
+
## Common Patterns
|
|
250
|
+
|
|
251
|
+
### Creating Scaled Units
|
|
252
|
+
|
|
253
|
+
```python
|
|
254
|
+
from ucon.core import Scale
|
|
255
|
+
from ucon import units
|
|
256
|
+
|
|
257
|
+
# Standard metric prefixes
|
|
258
|
+
km = Scale.kilo * units.meter
|
|
259
|
+
MHz = Scale.mega * units.hertz
|
|
260
|
+
ns = Scale.nano * units.second
|
|
261
|
+
|
|
262
|
+
# Binary prefixes (for information units)
|
|
263
|
+
KiB = Scale.kibi * units.byte
|
|
264
|
+
GiB = Scale.gibi * units.byte
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
### Scale Arithmetic in Practice
|
|
268
|
+
|
|
269
|
+
```python
|
|
270
|
+
# Velocity: km/h involves scale
|
|
271
|
+
km = Scale.kilo * units.meter
|
|
272
|
+
speed = (km / units.hour)(100) # 100 km/h
|
|
273
|
+
|
|
274
|
+
# Energy: kJ
|
|
275
|
+
kJ = Scale.kilo * units.joule
|
|
276
|
+
energy = kJ(4.184) # 4.184 kJ = 1 kcal
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
### Folding Scale into Quantity
|
|
280
|
+
|
|
281
|
+
```python
|
|
282
|
+
km = Scale.kilo * units.meter
|
|
283
|
+
distance = km(5)
|
|
284
|
+
|
|
285
|
+
# Get the scale factor
|
|
286
|
+
distance.unit.fold_scale() # 1000.0
|
|
287
|
+
|
|
288
|
+
# Canonical magnitude (quantity × scale)
|
|
289
|
+
distance._canonical_magnitude # 5000.0
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
---
|
|
293
|
+
|
|
294
|
+
## Testing Scale/Exponent Relationships
|
|
295
|
+
|
|
296
|
+
From `tests/ucon/test_core.py`:
|
|
297
|
+
|
|
298
|
+
```python
|
|
299
|
+
def test_scale_multiplication_same_base(self):
|
|
300
|
+
self.assertEqual(Scale.kilo * Scale.kilo, Scale.mega)
|
|
301
|
+
self.assertEqual(Scale.kilo * Scale.milli, Scale.one)
|
|
302
|
+
|
|
303
|
+
def test_scale_division(self):
|
|
304
|
+
self.assertEqual(Scale.mega / Scale.kilo, Scale.kilo)
|
|
305
|
+
self.assertEqual(Scale.kilo / Scale.mega, Scale.milli)
|
|
306
|
+
|
|
307
|
+
def test_scale_exponentiation(self):
|
|
308
|
+
self.assertEqual(Scale.kilo ** 2, Scale.mega)
|
|
309
|
+
self.assertEqual(Scale.milli ** -1, Scale.kilo)
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
From `tests/ucon/test_algebra.py`:
|
|
313
|
+
|
|
314
|
+
```python
|
|
315
|
+
def test_exponent_multiplication(self):
|
|
316
|
+
kibibyte = Exponent(2, 10)
|
|
317
|
+
mebibyte = Exponent(2, 20)
|
|
318
|
+
product = kibibyte * mebibyte
|
|
319
|
+
self.assertEqual(product.power, 30) # 2³⁰
|
|
320
|
+
|
|
321
|
+
def test_exponent_division_same_base(self):
|
|
322
|
+
thousand = Exponent(10, 3)
|
|
323
|
+
thousandth = Exponent(10, -3)
|
|
324
|
+
ratio = thousand / thousandth
|
|
325
|
+
self.assertEqual(ratio.power, 6) # 10⁶
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
---
|
|
329
|
+
|
|
330
|
+
## Summary
|
|
331
|
+
|
|
332
|
+
| Class | Module | Purpose |
|
|
333
|
+
|-------|--------|---------|
|
|
334
|
+
| `Exponent` | `ucon.algebra` | Base-power arithmetic (10³, 2¹⁰) |
|
|
335
|
+
| `ScaleDescriptor` | `ucon.core` | Wraps Exponent with shorthand/alias |
|
|
336
|
+
| `Scale` | `ucon.core` | Enum of named prefixes with algebra |
|
|
337
|
+
|
|
338
|
+
The relationship flows downward:
|
|
339
|
+
- `Scale.kilo` → `ScaleDescriptor` → `Exponent(10, 3)`
|
|
340
|
+
|
|
341
|
+
Arithmetic flows upward:
|
|
342
|
+
- `Exponent` math → resolve to `Scale` via lookup or `nearest()`
|
|
343
|
+
|
|
344
|
+
This layered design provides:
|
|
345
|
+
- **Type safety**: Scale operations return Scale, not raw numbers
|
|
346
|
+
- **Algebraic closure**: `kilo * kilo = mega`, not just `1000000`
|
|
347
|
+
- **Human readability**: Quantities display with appropriate prefixes
|
|
@@ -23,7 +23,7 @@ setup(
|
|
|
23
23
|
maintainer_email='withtwoemms@gmail.com',
|
|
24
24
|
url='https://github.com/withtwoemms/ucon',
|
|
25
25
|
classifiers=[
|
|
26
|
-
'Development Status ::
|
|
26
|
+
'Development Status :: 4 - Beta',
|
|
27
27
|
'Intended Audience :: Developers',
|
|
28
28
|
'Intended Audience :: Education',
|
|
29
29
|
'Intended Audience :: Science/Research',
|