LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
unit.cpp
浏览该文件的文档.
1#include "unit.hpp"
2
3#include <sstream>
4#include <utility>
5
6namespace LMCAS {
7namespace {
8
9constexpr const char* kUnitOperation = "unit";
10
11bool valid_unit_character(char character) {
12 if (character >= 'a' && character <= 'z') {
13 return true;
14 }
15 if (character >= 'A' && character <= 'Z') {
16 return true;
17 }
18 if (character >= '0' && character <= '9') {
19 return true;
20 }
21 return character == '_';
22}
23
24bool valid_unit_name(const std::string& name) {
25 if (name.empty()) {
26 return false;
27 }
28 for (char character : name) {
29 if (!valid_unit_character(character)) {
30 return false;
31 }
32 }
33 return true;
34}
35
36} // namespace
37
38DimensionSignature::DimensionSignature(Exponents exponents)
39 : exponents_(std::move(exponents)) {
40 for (auto iterator = exponents_.begin(); iterator != exponents_.end();) {
41 if (iterator->second.is_zero()) {
42 iterator = exponents_.erase(iterator);
43 } else {
44 ++iterator;
45 }
46 }
47}
48
49DimensionSignature DimensionSignature::base(std::string name) {
50 Exponents exponents;
51 exponents.emplace(std::move(name), Rational(1));
52 return DimensionSignature(std::move(exponents));
53}
54
55DimensionSignature DimensionSignature::multiplied_by(
56 const DimensionSignature& other) const {
57 Exponents result = exponents_;
58 for (const auto& entry : other.exponents_) result[entry.first] = result[entry.first] + entry.second;
59 return DimensionSignature(std::move(result));
60}
61
62DimensionSignature DimensionSignature::divided_by(
63 const DimensionSignature& other) const {
64 Exponents result = exponents_;
65 for (const auto& entry : other.exponents_) result[entry.first] = result[entry.first] - entry.second;
66 return DimensionSignature(std::move(result));
67}
68
69DimensionSignature DimensionSignature::raised_to(const Rational& exponent) const {
70 Exponents result;
71 for (const auto& entry : exponents_) result.emplace(entry.first, entry.second * exponent);
72 return DimensionSignature(std::move(result));
73}
74
75std::string DimensionSignature::to_string() const {
76 if (exponents_.empty()) return "1";
77 std::ostringstream output;
78 bool first = true;
79 for (const auto& entry : exponents_) {
80 if (!first) output << '*';
81 output << entry.first;
82 if (entry.second != Rational(1)) output << '^' << entry.second.to_string();
83 first = false;
84 }
85 return output.str();
86}
87
88UnitSystem::UnitSystem() {
89 const auto length = DimensionSignature::base("m");
90 const auto mass = DimensionSignature::base("kg");
91 const auto time = DimensionSignature::base("s");
92 const auto current = DimensionSignature::base("A");
93 const auto temperature = DimensionSignature::base("K");
94 const auto amount = DimensionSignature::base("mol");
95 const auto luminous_intensity = DimensionSignature::base("cd");
96
97 units_.emplace("m", UnitDefinition{length, Rational(1)});
98 units_.emplace("kg", UnitDefinition{mass, Rational(1)});
99 units_.emplace("s", UnitDefinition{time, Rational(1)});
100 units_.emplace("A", UnitDefinition{current, Rational(1)});
101 units_.emplace("K", UnitDefinition{temperature, Rational(1)});
102 units_.emplace("mol", UnitDefinition{amount, Rational(1)});
103 units_.emplace("cd", UnitDefinition{luminous_intensity, Rational(1)});
104 units_.emplace("km", UnitDefinition{length, Rational(1000)});
105 units_.emplace("cm", UnitDefinition{length, Rational(1, 100)});
106 units_.emplace("mm", UnitDefinition{length, Rational(1, 1000)});
107 units_.emplace("min", UnitDefinition{time, Rational(60)});
108 units_.emplace("h", UnitDefinition{time, Rational(3600)});
109 units_.emplace("g", UnitDefinition{mass, Rational(1, 1000)});
110}
111
112Result<void> UnitSystem::declare_base_unit(const std::string& name) {
113 if (!valid_unit_name(name)) {
114 return Result<void>::failure(
115 CasErrc::InvalidArgument, "unit name is invalid", kUnitOperation);
116 }
117 if (units_.find(name) != units_.end()) {
118 return Result<void>::failure(
119 CasErrc::InvalidArgument, "unit name is already declared", kUnitOperation);
120 }
121 units_.emplace(name, UnitDefinition{DimensionSignature::base(name), Rational(1)});
122 return Result<void>::success();
123}
124
125Result<void> UnitSystem::declare_derived_unit(
126 const std::string& name, UnitDefinition definition) {
127 if (!valid_unit_name(name) || definition.scale_to_base.is_zero() ||
128 definition.scale_to_base < Rational(0)) {
129 return Result<void>::failure(
130 CasErrc::InvalidArgument, "derived unit definition is invalid", kUnitOperation);
131 }
132 if (units_.find(name) != units_.end()) {
133 return Result<void>::failure(
134 CasErrc::InvalidArgument, "unit name is already declared", kUnitOperation);
135 }
136 units_.emplace(name, std::move(definition));
137 return Result<void>::success();
138}
139
140Result<UnitDefinition> UnitSystem::resolve(const std::string& name) const {
141 const auto iterator = units_.find(name);
142 if (iterator == units_.end()) {
143 return Result<UnitDefinition>::failure(
144 CasErrc::UnitInvalid, "unit is not declared: " + name, kUnitOperation);
145 }
146 return Result<UnitDefinition>::success(iterator->second);
147}
148
149Result<Rational> UnitSystem::conversion_factor(
150 const std::string& source, const std::string& target) const {
151 auto source_unit = resolve(source);
152 if (!source_unit) return Result<Rational>::failure(source_unit.error());
153 auto target_unit = resolve(target);
154 if (!target_unit) return Result<Rational>::failure(target_unit.error());
155 if (source_unit.value().dimension != target_unit.value().dimension) {
156 return Result<Rational>::failure(
157 CasErrc::DimensionMismatch,
158 "unit conversion requires equal dimensions", kUnitOperation);
159 }
160 return Result<Rational>::success(
161 source_unit.value().scale_to_base / target_unit.value().scale_to_base);
162}
163
164} // namespace LMCAS
bool valid_unit_name(const std::string &name)
bool valid_unit_character(char character)
constexpr const char * kUnitOperation
定义 unit.cpp:9
@ Rational
Rational numbers
std::string UnitDefinition definition
__attribute__((visibility("default"))) Result< EqvProfile > eqv_profile_from_name(const std const std::string & name