Coverage for /usr/lib/python3/dist-packages/sympy/physics/units/prefixes.py: 67%
109 statements
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-14 15:55 +0200
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-14 15:55 +0200
1"""
2Module defining unit prefixe class and some constants.
4Constant dict for SI and binary prefixes are defined as PREFIXES and
5BIN_PREFIXES.
6"""
7from sympy.core.expr import Expr
8from sympy.core.sympify import sympify
11class Prefix(Expr):
12 """
13 This class represent prefixes, with their name, symbol and factor.
15 Prefixes are used to create derived units from a given unit. They should
16 always be encapsulated into units.
18 The factor is constructed from a base (default is 10) to some power, and
19 it gives the total multiple or fraction. For example the kilometer km
20 is constructed from the meter (factor 1) and the kilo (10 to the power 3,
21 i.e. 1000). The base can be changed to allow e.g. binary prefixes.
23 A prefix multiplied by something will always return the product of this
24 other object times the factor, except if the other object:
26 - is a prefix and they can be combined into a new prefix;
27 - defines multiplication with prefixes (which is the case for the Unit
28 class).
29 """
30 _op_priority = 13.0
31 is_commutative = True
33 def __new__(cls, name, abbrev, exponent, base=sympify(10), latex_repr=None):
35 name = sympify(name)
36 abbrev = sympify(abbrev)
37 exponent = sympify(exponent)
38 base = sympify(base)
40 obj = Expr.__new__(cls, name, abbrev, exponent, base)
41 obj._name = name
42 obj._abbrev = abbrev
43 obj._scale_factor = base**exponent
44 obj._exponent = exponent
45 obj._base = base
46 obj._latex_repr = latex_repr
47 return obj
49 @property
50 def name(self):
51 return self._name
53 @property
54 def abbrev(self):
55 return self._abbrev
57 @property
58 def scale_factor(self):
59 return self._scale_factor
61 def _latex(self, printer):
62 if self._latex_repr is None:
63 return r'\text{%s}' % self._abbrev
64 return self._latex_repr
66 @property
67 def base(self):
68 return self._base
70 def __str__(self):
71 return str(self._abbrev)
73 def __repr__(self):
74 if self.base == 10:
75 return "Prefix(%r, %r, %r)" % (
76 str(self.name), str(self.abbrev), self._exponent)
77 else:
78 return "Prefix(%r, %r, %r, %r)" % (
79 str(self.name), str(self.abbrev), self._exponent, self.base)
81 def __mul__(self, other):
82 from sympy.physics.units import Quantity
83 if not isinstance(other, (Quantity, Prefix)):
84 return super().__mul__(other)
86 fact = self.scale_factor * other.scale_factor
88 if fact == 1:
89 return 1
90 elif isinstance(other, Prefix):
91 # simplify prefix
92 for p in PREFIXES:
93 if PREFIXES[p].scale_factor == fact:
94 return PREFIXES[p]
95 return fact
97 return self.scale_factor * other
99 def __truediv__(self, other):
100 if not hasattr(other, "scale_factor"):
101 return super().__truediv__(other)
103 fact = self.scale_factor / other.scale_factor
105 if fact == 1:
106 return 1
107 elif isinstance(other, Prefix):
108 for p in PREFIXES:
109 if PREFIXES[p].scale_factor == fact:
110 return PREFIXES[p]
111 return fact
113 return self.scale_factor / other
115 def __rtruediv__(self, other):
116 if other == 1:
117 for p in PREFIXES:
118 if PREFIXES[p].scale_factor == 1 / self.scale_factor:
119 return PREFIXES[p]
120 return other / self.scale_factor
123def prefix_unit(unit, prefixes):
124 """
125 Return a list of all units formed by unit and the given prefixes.
127 You can use the predefined PREFIXES or BIN_PREFIXES, but you can also
128 pass as argument a subdict of them if you do not want all prefixed units.
130 >>> from sympy.physics.units.prefixes import (PREFIXES,
131 ... prefix_unit)
132 >>> from sympy.physics.units import m
133 >>> pref = {"m": PREFIXES["m"], "c": PREFIXES["c"], "d": PREFIXES["d"]}
134 >>> prefix_unit(m, pref) # doctest: +SKIP
135 [millimeter, centimeter, decimeter]
136 """
138 from sympy.physics.units.quantities import Quantity
139 from sympy.physics.units import UnitSystem
141 prefixed_units = []
143 for prefix_abbr, prefix in prefixes.items():
144 quantity = Quantity(
145 "%s%s" % (prefix.name, unit.name),
146 abbrev=("%s%s" % (prefix.abbrev, unit.abbrev)),
147 is_prefixed=True,
148 )
149 UnitSystem._quantity_dimensional_equivalence_map_global[quantity] = unit
150 UnitSystem._quantity_scale_factors_global[quantity] = (prefix.scale_factor, unit)
151 prefixed_units.append(quantity)
153 return prefixed_units
156yotta = Prefix('yotta', 'Y', 24)
157zetta = Prefix('zetta', 'Z', 21)
158exa = Prefix('exa', 'E', 18)
159peta = Prefix('peta', 'P', 15)
160tera = Prefix('tera', 'T', 12)
161giga = Prefix('giga', 'G', 9)
162mega = Prefix('mega', 'M', 6)
163kilo = Prefix('kilo', 'k', 3)
164hecto = Prefix('hecto', 'h', 2)
165deca = Prefix('deca', 'da', 1)
166deci = Prefix('deci', 'd', -1)
167centi = Prefix('centi', 'c', -2)
168milli = Prefix('milli', 'm', -3)
169micro = Prefix('micro', 'mu', -6, latex_repr=r"\mu")
170nano = Prefix('nano', 'n', -9)
171pico = Prefix('pico', 'p', -12)
172femto = Prefix('femto', 'f', -15)
173atto = Prefix('atto', 'a', -18)
174zepto = Prefix('zepto', 'z', -21)
175yocto = Prefix('yocto', 'y', -24)
178# https://physics.nist.gov/cuu/Units/prefixes.html
179PREFIXES = {
180 'Y': yotta,
181 'Z': zetta,
182 'E': exa,
183 'P': peta,
184 'T': tera,
185 'G': giga,
186 'M': mega,
187 'k': kilo,
188 'h': hecto,
189 'da': deca,
190 'd': deci,
191 'c': centi,
192 'm': milli,
193 'mu': micro,
194 'n': nano,
195 'p': pico,
196 'f': femto,
197 'a': atto,
198 'z': zepto,
199 'y': yocto,
200}
203kibi = Prefix('kibi', 'Y', 10, 2)
204mebi = Prefix('mebi', 'Y', 20, 2)
205gibi = Prefix('gibi', 'Y', 30, 2)
206tebi = Prefix('tebi', 'Y', 40, 2)
207pebi = Prefix('pebi', 'Y', 50, 2)
208exbi = Prefix('exbi', 'Y', 60, 2)
211# https://physics.nist.gov/cuu/Units/binary.html
212BIN_PREFIXES = {
213 'Ki': kibi,
214 'Mi': mebi,
215 'Gi': gibi,
216 'Ti': tebi,
217 'Pi': pebi,
218 'Ei': exbi,
219}