LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
numeric_literal.hpp
浏览该文件的文档.
1#pragma once
2
3#include "result.hpp"
4#include <cmath>
5#include <string_view>
6#ifdef __APPLE__
7#include <cstdlib>
8#include <locale.h>
9#include <string>
10#else
11#include <charconv>
12#include <system_error>
13#endif
14
15namespace LMCAS::detail {
16
17inline bool consume_decimal_digits(std::string_view token, std::size_t& pos) noexcept {
18 const auto start = pos;
19 while (pos < token.size() && token[pos] >= '0' && token[pos] <= '9') {
20 ++pos;
21 }
22 return pos != start;
23}
24
25inline bool consume_decimal_mantissa(std::string_view token, std::size_t& pos) noexcept {
26 bool has_digits = consume_decimal_digits(token, pos);
27 if (pos < token.size() && token[pos] == '.') {
28 ++pos;
29 has_digits = consume_decimal_digits(token, pos) || has_digits;
30 }
31 return has_digits;
32}
33
34inline void consume_decimal_sign(std::string_view token, std::size_t& pos) noexcept {
35 if (pos < token.size() && (token[pos] == '+' || token[pos] == '-')) {
36 ++pos;
37 }
38}
39
40inline bool consume_decimal_exponent(std::string_view token, std::size_t& pos) noexcept {
41 if (pos < token.size() && (token[pos] == 'e' || token[pos] == 'E')) {
42 ++pos;
43 consume_decimal_sign(token, pos);
44 return consume_decimal_digits(token, pos);
45 }
46 return true;
47}
48
49inline bool is_signed_decimal_token(std::string_view token) noexcept {
50 std::size_t pos = 0;
51 consume_decimal_sign(token, pos);
52 if (!consume_decimal_mantissa(token, pos)) { return false; }
53 if (!consume_decimal_exponent(token, pos)) { return false; }
54 return pos == token.size();
55}
56
57inline Result<double> parse_finite_decimal(std::string_view token) {
58 const auto invalid = [] {
60 "expected a representable finite decimal", "LMCAS.numeric_literal");
61 };
62 if (!is_signed_decimal_token(token)) { return invalid(); }
63 if (token.front() == '+') { token.remove_prefix(1); }
64 double value = 0;
65#ifdef __APPLE__
66 // Xcode 16 uses strtod_l with a fixed C locale for decimal conversion.
67 static const locale_t c_locale = newlocale(LC_NUMERIC_MASK, "C", nullptr);
68 if (!c_locale) { return invalid(); }
69 std::string text(token);
70 char* end = nullptr;
71 value = strtod_l(text.c_str(), &end, c_locale);
72 const bool converted = end == text.c_str() + text.size();
73#else
74 const auto parsed = std::from_chars(token.data(), token.data() + token.size(),
75 value, std::chars_format::general);
76 const bool converted = parsed.ec == std::errc{} &&
77 parsed.ptr == token.data() + token.size();
78#endif
79 if (!converted || !std::isfinite(value)) { return invalid(); }
80 if (value == 0) {
81 for (char c : token) {
82 if (c == 'e' || c == 'E') { break; }
83 if (c >= '1' && c <= '9') { return invalid(); }
84 }
85 if (token.front() == '-') { value = -0.0; }
86 }
87 return value;
88}
89
90}
static Result failure(CasErrc code, std::string message, std::string operation={})
多元 Hensel 提升(单变量步)
Result< double > parse_finite_decimal(std::string_view token)
bool consume_decimal_mantissa(std::string_view token, std::size_t &pos) noexcept
bool consume_decimal_exponent(std::string_view token, std::size_t &pos) noexcept
bool consume_decimal_digits(std::string_view token, std::size_t &pos) noexcept
bool is_signed_decimal_token(std::string_view token) noexcept
void consume_decimal_sign(std::string_view token, std::size_t &pos) noexcept
const VectorField const VectorField & c
const std::string const ExprPtr & value