【问题标题】:Bad calculations after Python to C# portPython 到 C# 端口后的错误计算
【发布时间】:2012-08-05 00:37:45
【问题描述】:

我正在研究基于 Reddit 模型的帖子系统的时间衰减算法: http://amix.dk/blog/post/19588

我的工作端口在这里:

public class Calculation
{
    protected DateTime Epoch = new DateTime(1970, 1, 1);

    protected long EpochSeconds(DateTime dt)
    {
        var ts = dt.Subtract(Convert.ToDateTime("1/1/1970 8:00:00 AM"));

        return ((((((ts.Days * 24) + ts.Hours) * 60) + ts.Minutes) * 60) + ts.Seconds);
    }

    protected int Score(int upVotes, int downVotes)
    {
        return upVotes - downVotes;
    }

    public double HotScore(int upVotes, int downVotes, DateTime date)
    {
        var s = Score(upVotes, downVotes);
        var order = Math.Log(Math.Max(Math.Abs(s), 1), 10);
        var sign = Math.Sign(s);
        var seconds = EpochSeconds(date) - 1134028003;
        return Math.Round(order + sign * ((double)seconds / 45000), 7);
    }
}

根据所提供链接的模型输出,我应该会在 0-13 小时看到逐渐衰减,之后会急剧衰减。

我看到的是非常均匀的衰减,并且得分远高于原始代码的输出(原始代码:3480-3471)。

这是我的测试方式:

        Calculation c = new Calculation();
        double now = c.HotScore(100, 2, DateTime.Now);
        double fivehoursago = c.HotScore(100, 2, DateTime.Now.AddHours(-5));
        double tenhoursago = c.HotScore(100, 2, DateTime.Now.AddHours(-10));
        double elevenhoursago = c.HotScore(100, 2, DateTime.Now.AddHours(-11));
        double twelvehoursago = c.HotScore(100, 2, DateTime.Now.AddHours(-12));
        double thirteenhoursago = c.HotScore(100, 2, DateTime.Now.AddHours(-13));
        double fiftyhoursago = c.HotScore(100, 2, DateTime.Now.AddHours(-50));
        double onehundredhoursago = c.HotScore(100, 2, DateTime.Now.AddHours(-100));
        Console.WriteLine(now.ToString());
        Console.WriteLine(fivehoursago.ToString());
        Console.WriteLine(tenhoursago.ToString());
        Console.WriteLine(elevenhoursago.ToString());
        Console.WriteLine(twelvehoursago.ToString());
        Console.WriteLine(thirteenhoursago.ToString());
        Console.WriteLine(fiftyhoursago.ToString());
        Console.WriteLine(onehundredhoursago.ToString());
        Console.ReadLine();

输出值:

now:               4675.2993816
five hours:        4674.8993816
ten hours:         4674.4993816
eleven hours:      4674.4193816
twelve hours:      4674.3393816
thirteen hours:    4674.2593816
fifty hours:       4671.2993816
one-hundred hours: 4667.2993816

很明显,它工作正常,但有些不对劲。这可能与缺乏真正的 *nix Epoch 支持或缺乏类似的微秒计算有关,但有些地方不太正确。

可能的参考资源: http://blogs.msdn.com/b/brada/archive/2004/03/20/93332.aspx http://codeclimber.net.nz/archive/2007/07/10/convert-a-unix-timestamp-to-a-.net-datetime.aspx

【问题讨论】:

    标签: c# python math time port


    【解决方案1】:

    您的主要问题是热算法是时间相关的。您在DateTime.Now 计算热门分数,而这篇文章写于 2010 年 11 月 23 日(请看文章底部)。

    经过反复试验,数据似乎是在大约 2010 年 11 月 23 日 07:35 计算的。尝试使用该值而不是 DateTime.Now,您应该会得到与图中所示数据大致相同的结果。

    请注意,您可以对代码进行以下改进:

    public class Calculation
    {
        private static readonly DateTime Epoch = new DateTime(1970, 1, 1);
    
        private double EpochSeconds(DateTime dt)
        {
            return (dt - Epoch).TotalSeconds;
        }
    
        private int Score(int upVotes, int downVotes)
        {
            return upVotes - downVotes;
        }
    
        public double HotScore(int upVotes, int downVotes, DateTime date)
        {
            int s = Score(upVotes, downVotes);
            double order = Math.Log(Math.Max(Math.Abs(s), 1), 10);
            int sign = Math.Sign(s);
            double seconds = EpochSeconds(date) - 1134028003;
            return Math.Round(order + sign * seconds / 45000, 7);
        }
    }
    

    我的结果:

    3479.0956039
    3478.6956039
    3478.2956039
    3478.2156039
    3478.1356039
    3478.0556039
    3475.0956039
    3471.0956039
    

    变化:

    • 使用声明的 Epoch 而不是 1970-01-01 08:00:00 的转换(我认为 08:00 是一个错误)。
    • 您可以使用a - b 减去两个日期;这与a.Subtract(b) 相同,但更简洁,它反映了原始 Python 代码。
    • 时间跨度确实为您提供微秒精度(刻度是最小单位,等于 100 纳秒)。
    • 此外,TotalSeconds 为您提供时间跨度内的总秒数;无需重新计算。小数部分甚至可以为您提供微秒级精度。
    • 通过从 EpochSeconds 返回双精度,您可以保持此精度。
    • 使数据类型显式而不是 var 以清楚地指示什么变量是什么(它们与方法签名匹配,因此没有隐式向上转换)。
    • 将不需要的 protected 更改为 private 并将 Epoch 设为常量。

    【讨论】:

    • 只需要下班回来验证,但我要说谢谢你花这么多时间做这件事。我知道回答简短的问题更容易:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-05
    • 1970-01-01
    相关资源
    最近更新 更多