|
|
@@ -27,7 +27,7 @@ class SymjaEntry {
|
|
|
final DateTime at;
|
|
|
|
|
|
SymjaEntry({required this.input, this.result, this.error, DateTime? at})
|
|
|
- : at = at ?? DateTime.now();
|
|
|
+ : at = at ?? DateTime.now();
|
|
|
|
|
|
bool get ok => result != null;
|
|
|
}
|
|
|
@@ -97,7 +97,7 @@ class SymjaSession extends ChangeNotifier {
|
|
|
/// 也是符号计算的意义所在,所以默认不开。开起来时给表达式套一层 `N[expr, 30]`。
|
|
|
bool approximate = false;
|
|
|
|
|
|
- /// 近似模式下的有效位数。
|
|
|
+ /// 近似模式下保留几位**小数**。
|
|
|
///
|
|
|
/// 15 位是刻意选的:再高就放不下了。`N[1/3, 30]` 会给出三十多个字符的长串,
|
|
|
/// 手机上怎么看都显示不全(用户实测反馈)。15 位比一般科学计算器还多,
|
|
|
@@ -114,7 +114,8 @@ class SymjaSession extends ChangeNotifier {
|
|
|
String _applyMode(String expr) {
|
|
|
if (!approximate) return expr;
|
|
|
if (_assignment.hasMatch(expr)) return expr;
|
|
|
- return 'N[$expr, $approximateDigits]';
|
|
|
+ // 保留 k 位小数。用 Round 而不是 N[expr, k]:Symja 的 N 忽略第二个参数
|
|
|
+ return 'N[Round[$expr, 1/10^$approximateDigits]]';
|
|
|
}
|
|
|
|
|
|
int _seq = 0;
|
|
|
@@ -145,14 +146,17 @@ class SymjaSession extends ChangeNotifier {
|
|
|
notifyListeners();
|
|
|
|
|
|
try {
|
|
|
- final m = await symjaChannel.invokeMapMethod<String, dynamic>('evaluate', {
|
|
|
- 'taskId': id,
|
|
|
- 'expr': _applyMode(input),
|
|
|
- 'timeoutMs': timeout.inMilliseconds,
|
|
|
- 'wantTeX': wantTeX,
|
|
|
- // 显式声明这不是预览:预览不更新 `%`,正式求值要更新
|
|
|
- 'preview': false,
|
|
|
- });
|
|
|
+ final m = await symjaChannel.invokeMapMethod<String, dynamic>(
|
|
|
+ 'evaluate',
|
|
|
+ {
|
|
|
+ 'taskId': id,
|
|
|
+ 'expr': _applyMode(input),
|
|
|
+ 'timeoutMs': timeout.inMilliseconds,
|
|
|
+ 'wantTeX': wantTeX,
|
|
|
+ // 显式声明这不是预览:预览不更新 `%`,正式求值要更新
|
|
|
+ 'preview': false,
|
|
|
+ },
|
|
|
+ );
|
|
|
|
|
|
if (m == null || m['ok'] != true) {
|
|
|
_record(input, error: '${m?['error'] ?? '原生侧返回了空结果'}');
|
|
|
@@ -187,13 +191,16 @@ class SymjaSession extends ChangeNotifier {
|
|
|
final input = expr.trim();
|
|
|
if (input.isEmpty) return null;
|
|
|
try {
|
|
|
- final m = await symjaChannel.invokeMapMethod<String, dynamic>('evaluate', {
|
|
|
- 'taskId': ++_seq,
|
|
|
- 'expr': _applyMode(input),
|
|
|
- 'timeoutMs': 4000,
|
|
|
- 'wantTeX': true,
|
|
|
- 'preview': true,
|
|
|
- });
|
|
|
+ final m = await symjaChannel.invokeMapMethod<String, dynamic>(
|
|
|
+ 'evaluate',
|
|
|
+ {
|
|
|
+ 'taskId': ++_seq,
|
|
|
+ 'expr': _applyMode(input),
|
|
|
+ 'timeoutMs': 4000,
|
|
|
+ 'wantTeX': true,
|
|
|
+ 'preview': true,
|
|
|
+ },
|
|
|
+ );
|
|
|
if (m == null || m['ok'] != true) return null;
|
|
|
return SymjaResult(
|
|
|
text: '${m['text']}',
|
|
|
@@ -223,18 +230,21 @@ class SymjaSession extends ChangeNotifier {
|
|
|
final input = expr.trim();
|
|
|
if (input.isEmpty) throw const SymjaException('表达式为空');
|
|
|
try {
|
|
|
- final m = await symjaChannel.invokeMapMethod<String, dynamic>('evaluate', {
|
|
|
- 'taskId': ++_seq,
|
|
|
- // 工具页传 applyMode: false —— 它在表达式里自己写 N[...],
|
|
|
- // 不该被计算器顶栏那个"精确 / 近似"开关二次改写(否则"精确值"
|
|
|
- // 那一条也会变成近似值,两条输出就没区别了)。
|
|
|
- 'expr': applyMode ? _applyMode(input) : input,
|
|
|
- 'timeoutMs': timeout.inMilliseconds,
|
|
|
- 'wantTeX': wantTeX,
|
|
|
- // preview=true 同时意味着原生侧不更新 lastOutput,
|
|
|
- // 所以工具算完不会顶掉用户在计算器上按 ANS 拿到的东西。
|
|
|
- 'preview': true,
|
|
|
- });
|
|
|
+ final m = await symjaChannel.invokeMapMethod<String, dynamic>(
|
|
|
+ 'evaluate',
|
|
|
+ {
|
|
|
+ 'taskId': ++_seq,
|
|
|
+ // 工具页传 applyMode: false —— 它在表达式里自己写 N[...],
|
|
|
+ // 不该被计算器顶栏那个"精确 / 近似"开关二次改写(否则"精确值"
|
|
|
+ // 那一条也会变成近似值,两条输出就没区别了)。
|
|
|
+ 'expr': applyMode ? _applyMode(input) : input,
|
|
|
+ 'timeoutMs': timeout.inMilliseconds,
|
|
|
+ 'wantTeX': wantTeX,
|
|
|
+ // preview=true 同时意味着原生侧不更新 lastOutput,
|
|
|
+ // 所以工具算完不会顶掉用户在计算器上按 ANS 拿到的东西。
|
|
|
+ 'preview': true,
|
|
|
+ },
|
|
|
+ );
|
|
|
if (m == null || m['ok'] != true) {
|
|
|
throw SymjaException('${m?['error'] ?? '未知错误'}');
|
|
|
}
|
|
|
@@ -359,10 +369,12 @@ class SymjaSession extends ChangeNotifier {
|
|
|
/// 从存档恢复历史。不触发求值。
|
|
|
void restoreHistory(Iterable<({String input, String text, int ms})> entries) {
|
|
|
for (final e in entries) {
|
|
|
- history.add(SymjaEntry(
|
|
|
- input: e.input,
|
|
|
- result: SymjaResult(text: e.text, tex: null, elapsedMs: e.ms),
|
|
|
- ));
|
|
|
+ history.add(
|
|
|
+ SymjaEntry(
|
|
|
+ input: e.input,
|
|
|
+ result: SymjaResult(text: e.text, tex: null, elapsedMs: e.ms),
|
|
|
+ ),
|
|
|
+ );
|
|
|
}
|
|
|
while (history.length > maxHistory) {
|
|
|
history.removeAt(0);
|