math - 将罗马数字翻译成阿拉伯数字

标签 math integer prolog converters roman-numerals

我构建了一个谓词,可将罗马数字转换为阿拉伯数字。唯一的问题是谓词是有限的:如果我想一次转换超过 3 个阿拉伯数字,它就不再起作用了。

谓词应该是这样工作的:

?- convert([v,i,i],Arabic).
Arabic = 7.

到目前为止我的解决方案:

tran([],0).
tran(i,1).
tran(v,5).
tran(x,10).

convert([],X) :- X is 0, !.
convert([T],X) :- tran(T,E), X is E,!.
convert([T|Ts],X) :- tran(T,E), tran(Ts,Es), X is E+Es,!.
convert([T,Ts,Tss],X) :- tran(T,E), tran(Ts,Es), tran(Tss,Ess), X is E+Es+Ess.

我知道为什么谓词不能处理超过 3 个数字,我也可以扩展转换谓词,但使用与上面所示相同的模式。

如何使转换谓词更“通用”(以便它可以独立于数字的数量工作)?或者您对如何编写谓词有其他想法? 谢谢:)

最佳答案

我没有对此进行太多测试,但我已经在多个数字上进行了尝试,它似乎有效。

该代码遵循“减法对规则”,例如在 https://projecteuler.net/about=roman_numerals 中进行了描述

该代码使用“累加器”技术来传递信息,即之前看到的数字总和。初始调用只是将累加器设置为 0。

digit(i, 1).
digit(v, 5).
digit(x, 10).
digit(l, 50).
digit(c, 100).
digit(d, 500).
digit(m, 1000).

convert(Roman, Arabic) :-
    convert(Roman, 0, Arabic).

convert([], Acc, Acc).

convert([A], Acc, Arabic) :-
    digit(A, AVal),
    Arabic is Acc + AVal.

convert([A, B | Rest], Acc, Arabic) :-
    digit(A, AVal), digit(B, BVal),
    AVal < BVal,
    NewAcc is Acc + BVal - AVal,
    convert(Rest, NewAcc, Arabic).

convert([A, B | Rest], Acc, Arabic) :-
    digit(A, AVal), digit(B, BVal),
    AVal >= BVal,
    NewAcc is Acc + AVal,
    convert([B | Rest], NewAcc, Arabic).

一些测试:

convert([v, i, i], Arabic).
Arabic = 7 

?- convert([x, i, x], Arabic).
Arabic = 19 

?- convert([m, d, c, v, i], Arabic).
Arabic = 1606 

可能可以使用约束编程编写一个谓词 convert,它以真正的 Prolog 精神双向工作,但我还没有尝试过这种方法。

关于math - 将罗马数字翻译成阿拉伯数字,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21538970/

相关文章:

string - LZ 77 压缩算法

php - 通过 PHP 在 MySQL 中查询整数

prolog - CLP(FD) 可变域和传播

prolog - prolog 中列表的公共(public)子序列

prolog - Prolog 中带有上限的事实形成

algorithm - big-O notation 和 theta notation 的区别,为什么 (theta) Ө-notation 适合插入排序来描述其最坏情况运行时间?

algorithm - 计算 nCr 模 p,一个素数

c# - 双淘汰括号算法

java - Java中如何检查字符串的名称是否与整数的名称相同?

java - 从字符串中获取资源id