如何强制C#二进制整数除法返回双精度浮点数?

5
如何强制使 double x = 3 / 2; 返回 x = 1.5 而不需要添加 D 后缀或进行类型转换?是否有某种运算符重载或编译器选项可用?
令人惊讶的是,由于以下原因,添加类型转换或后缀并不简单:
业务用户需要编写和调试自己的公式。目前,C# 正在像 DSL(特定领域语言)一样使用,这些用户不是计算机科学工程师。因此,他们只知道如何编辑和创建几种类型的类来保存他们的“业务规则”,这些规则通常只是数学公式。
但他们总是认为 double x = 3 / 2; 将返回 x = 1.5,然而在 C# 中,它返回 1。
A. 他们总是忘记这一点,浪费时间调试,然后打电话给我寻求支持,我们会解决它。 B. 他们认为这非常丑陋,影响了业务规则的可读性。
正如您所知,DSL 需要更像自然语言。
是的。我们计划转向 Boo 并基于此构建 DSL,但这是将来的事情。
有没有简单的解决方案可以通过类外部的方式使 double x = 3 / 2; 返回 1.5,以便对用户不可见?
谢谢! Wayne

7
C#不是DSL,它是一种通用的编程语言,用于创建库和应用程序。如果允许非程序员编写并将C#代码集成到代码库中,那么你已经输了。如果需要提供脚本支持,则应将脚本引擎嵌入到应用程序中。如果时间紧迫,则可以创建一个简化的、特定目的的语法或者UI来构建这些数学公式,以便在真正的代码中解释它们。 - Aaronaught
9个回答

5

没有任何解决方案可以使3 / 2返回1.5。

唯一的解决方法是鼓励用户在公式中使用常量,而不是字面量。如果他们确实需要使用字面量,请鼓励他们使用带小数点的字面量。


1
除了那些有解决方案的,其他都不行。 - John K
请翻译以下与编程有关的内容,从英文到中文。只返回已翻译的文本:类似解决方案https://dev59.com/sUzSa4cB1Zd3GeqPorL0#2485892...就像你提到的那样,但我可能会在第一句之后或之前进行评论。所以毕竟没有不同意的上下文。 - John K
1
直到我们使用DSL之前,鼓励用户使用3.0 / 2.0的建议是可行的。有些用户从不阅读手册,而是只跟随示例代码,用户数量正在增长,无法亲自教授他们。因此,我将修改所有示例代码和公式,让他们使用3.0 / 2.0语法。这样新用户就会自动模仿。而且他们非常聪明,所以他们会立即猜测如果去掉“.0”并获得整数结果的原因。换句话说,3.0 / 2.0是不言自明的,而3D / 2D绝对不是。 - Wayne

1

永远不要说永远...... (双)3/2的解看起来很好......

但是对于4+5/6它失败了

试试这个: 捐赠给公共领域,可以自由地使用SymbolicComputation.com。
它还处于测试阶段,但您可以尝试一下,我只在一些测试中运行过它,我的网站和软件即将上线。 它使用Microsoft的Roslyn,如果一切顺利,它会在每个数字后面加上一个“d”。 Roslyn也处于测试阶段,但它可以解析相当多的C#。

    public static String AddDSuffixesToEquation(String inEquation)
    {
        SyntaxNode syntaxNode = EquationToSyntaxNode(inEquation);
        List<SyntaxNode> branches = syntaxNode.DescendentNodesAndSelf().ToList();
        List<Int32> numericBranchIndexes = new List<int>();
        List<SyntaxNode> replacements = new List<SyntaxNode>();
        SyntaxNode replacement;
        String lStr;
        Int32 L;
        for (L = 0; L < branches.Count; L++)
        {
            if (branches[L].Kind == SyntaxKind.NumericLiteralExpression)
            {
                numericBranchIndexes.Add(L);
                lStr = branches[L].ToString() + "d";
                replacement = EquationToSyntaxNode(lStr);
                replacements.Add(replacement);
            }
        }

        replacement = EquationToSyntaxNode(inEquation);
        List<SyntaxNode> replaceMeBranches;
        for (L = numericBranchIndexes.Count - 1; L >= 0; L--)
        {
            replaceMeBranches = replacement.DescendentNodesAndSelf().ToList();
            replacement = replacement.ReplaceNode(replaceMeBranches[numericBranchIndexes[L]],replacements[L]);
        }
        return replacement.ToString();

    }

    public static SyntaxNode EquationToSyntaxNode(String inEquation)
    {
        SyntaxTree tree = EquationToSyntaxTree(inEquation);
        return EquationSyntaxTreeToEquationSyntaxNode(tree);
    }

    public static SyntaxTree EquationToSyntaxTree(String inEquation)
    {
        return SyntaxTree.ParseCompilationUnit("using System; class Calc { public static object Eval() { return " + inEquation + "; } }");
    }

    public static SyntaxNode EquationSyntaxTreeToEquationSyntaxNode(SyntaxTree syntaxTree)
    {
        SyntaxNode syntaxNode = syntaxTree.Root.DescendentNodes().First(x => x.Kind == SyntaxKind.ReturnStatement);
        return syntaxNode.ChildNodes().First();
    }

0

尝试像这样做:

double result = (double) 3 / 2;

结果 = 1.5


0

简单,如果我没记错的话:

double x = 3D / 2D;

提问者说:没有D后缀或强制转换。 - Anzurio

0
一个解决方案是编写一个方法来为他们完成这个任务,并教他们如何使用它。您的方法将始终接受双精度浮点数,并且答案将始终具有正确的小数位数。

0

我不能确定,但我相信你可以使用3.0/2.0获得一个double类型的值。 但是,如果你把.0看作后缀的另一种方式,那么这也不是答案 :-)


这只是一个猜测,而不是答案。回答那些在你专业范围内的问题。错误的答案会使寻找有用建议变得更加困难。 - Bob Kaufman

0

也许你现在可以尝试一下RPN表达式解析器类或者bcParser?这些都是非常小的表达式解析库。

对于我的工作,我喜欢强类型语言,但我认为它们不适合那些没有成为专业人士兴趣的初学者。

所以,不幸的是,我必须说你选择C#可能不是最适合那个受众群体的。

Boo似乎也是静态类型的。你有没有考虑过嵌入一个Javascript引擎、Python或其他动态类型引擎?这些通常不难插入到现有应用程序中,并且你可以获得大量现有文档的好处。


Python 3.0 之前的版本在除法方面存在相同的问题。 - dan04
用户都喜欢C#,因为他们的首要考虑是性能。系统的关键路径代码是使用指针编写的不安全代码,所以他们说这是交易行业中最快的软件。因此,他们暂时忍受C#,直到我们可以创建一个完整的DSL。 - Wayne
就语言选择而言,Boo似乎是最好的选择,因为它是可扩展的。也就是说,在编译过程的任何步骤中,您都可以更改解析器树中的任何内容。我唯一担心的是,调试器功能和C#可用的自动代码完成非常重要。如果使用修改后的Boo语言,我还不确定业务用户能否继续通过代码进行调试。 - Wayne

0

也许是 int32 的扩展方法?


我非常希望这可以成为一个解决方案并进行了专门的研究,甚至尝试过。但是,据C#语言作者所说,你不能按扩展方法创建运算符重载器。如果我错了,请纠正我。 - Wayne

0

在将公式传递给C#编译器之前,对其进行预处理。可以执行以下操作:

formula = Regex.Replace(formula, @"(^|[\^\s\+\*\/-])(\d+)(?![DF\.])", "$1$2D")

将整数字面量转换为双精度字面量。

或者,您可以使用一个简单的状态机来跟踪您是否在字符串字面量或注释中,而不是盲目地替换,但对于简单的公式,我认为正则表达式就足够了。


非常聪明。 "公式" 实际上是带有条件和子方法的完整方法。在公式之上,这是相当复杂的逻辑。具体来说,这些是自动交易规则。 - Wayne

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接