草庐IT

go - 略有不同的 float 学结果(C 到 golang)

coder 2023-06-30 原文

我正致力于直接在 golang 中开发技术指标库。除其他外,它是学习 golang 的练习。

我一直在通过使用 TA-Lib(或者更确切地说是围绕 TA-Lib 的 ruby​​ 包装器)生成的数据构建测试用例来验证我的算法的结果。

在我开始实现布林带之前,这一直运行良好。我的实现似乎工作正常,但在小数点后 14-15 位有所不同。

我读过 Floating point math in different programming languages并怀疑这可能是罪魁祸首(我以稍微不同的顺序进行计算)。

编辑添加:

上面的问题涉及 float 学的一个非常简单的表现形式。很难确认一段较长的代码是否真的解决了这个问题。

我如何确认它只是 float 学因顺序而发生的变化?

/结束编辑

我的理解正确吗?

这是我的实现:

package ta

import (
  "math"
)

func BollingerBands(values []float64, period int) ([]float64, []float64, []float64) {
  deviationsUp := 2.0
  deviationsDown := 2.0

  middleBand := Sma(values, period)
  offset := len(values)-len(middleBand)
  var upperBand []float64
  var lowerBand []float64
  for idx, v := range middleBand {
    backIdx := offset+idx-period+1
    curIdx := offset+idx+1
    if backIdx < 0 {
      backIdx = 0
    }
    stdDev := SliceStdDev(values[backIdx:curIdx])
    upperBand = append(upperBand, v + (stdDev * deviationsUp))
    lowerBand = append(lowerBand, v - (stdDev * deviationsDown))
  }
  return upperBand, middleBand, lowerBand
}

// Sma produces the Simple Moving Average for the
// supplied array of float64 values for a given period
func Sma(values []float64, period int) []float64{
  var result []float64
  for index,_ := range values {
    indexPlusOne := index+1
    if(indexPlusOne>=period) {
      avg := Mean(values[indexPlusOne-period:indexPlusOne])
      result = append(result, avg)
    }
  }
  return result
}

// SliceMean returns the Mean of the slice of float64
func SliceMean(values []float64) float64 {
  var total float64=0
    for _,element := range values {
        total += element
    }
  return total / float64(len(values))
}

// SliceVariance returns the variance of the slice of float64.
func SliceVariance(values []float64) float64 {
    if 0 == len(values) {
        return 0.0
    }
    m := SliceMean(values)
    var sum float64
    for _, v := range values {
        d := v - m
        sum += d * d
    }
    return sum / float64(len(values))
}

// SliceStdDev returns the standard deviation of the slice of float64.
func SliceStdDev(values []float64) float64 {
    return math.Sqrt(SliceVariance(values))
}

这会导致上频带的以下值 <[]float64 | len:6, cap:8>: [94.92564730599291, 94.50588827974477, 92.12752961253167, 101.58367006802706, 114.64331379078675, 120.58088881180322]

使用 ruby :

require 'indicator/mixin'
x = [26.0, 54.0, 8.0, 77.0, 61.0, 39.0, 44.0, 91.0, 98.0, 17.0]
y = x.indicator(:bbands_5)
# {:out_real_upper_band=>[94.9256473059929, 94.50588827974477, 92.12752961253167, 101.58367006802709, 114.64331379078678, 120.58088881180323, nil, nil, nil, nil] <SNIP>}

最佳答案

我认为算法不同。例如variance :

/* Do the MA calculation using tight loops. */
/* Add-up the initial periods, except for the last value. */
periodTotal1 = 0;
periodTotal2 = 0;
trailingIdx = startIdx-nbInitialElementNeeded;

i=trailingIdx;
if( optInTimePeriod > 1 )
{
   while( i < startIdx ) {
      tempReal = inReal[i++];
      periodTotal1 += tempReal;
      tempReal *= tempReal;
      periodTotal2 += tempReal;
   }
}

/* Proceed with the calculation for the requested range.
 * Note that this algorithm allows the inReal and
 * outReal to be the same buffer.
 */
outIdx = 0;
do
{
   tempReal = inReal[i++];

   /* Square and add all the deviation over
    * the same periods.
    */

   periodTotal1 += tempReal;
   tempReal *= tempReal;
   periodTotal2 += tempReal;

   /* Square and add all the deviation over
    * the same period.
    */

   meanValue1 = periodTotal1 / optInTimePeriod;
   meanValue2 = periodTotal2 / optInTimePeriod;

   tempReal = inReal[trailingIdx++];
   periodTotal1 -= tempReal;
   tempReal *= tempReal;
   periodTotal2 -= tempReal;

   outReal[outIdx++] = meanValue2-meanValue1*meanValue1;
} while( i <= endIdx );

这看起来不像你的方差。如果您要重现这些算法以便它们执行完全相同的操作,那么 Go 版本应该会产生相同的结果。 Go 只是在做标准的 IEEE 754 浮点运算。

关于“顺序重要吗?”这个问题确实如此。由于浮点运算是不精确的,因此您在进行计算时会丢失信息。大多数时候它并没有太大的区别,但有时算法可能很容易受到这些变化的影响。 (因此以代数方式重新排列您的公式可能不会在实际代码中得到相同的答案)

您经常会在类似这样的库中发现算法是为解决这些问题而设计的,因此它们通常看起来不像简单的实现。例如mean通常是一个微不足道的函数,但这是它在 GSL 中的计算方式:

double
FUNCTION (gsl_stats, mean) (const BASE data[], const size_t stride, const size_t size)
{
  /* Compute the arithmetic mean of a dataset using the recurrence relation 
     mean_(n) = mean(n-1) + (data[n] - mean(n-1))/(n+1)   */

  long double mean = 0;
  size_t i;

  for (i = 0; i < size; i++)
    {
      mean += (data[i * stride] - mean) / (i + 1);
    }

  return mean;
}

因此,除非您完全匹配算法,否则您的答案将略有不同。 (这并不一定意味着你的程序是错误的)

通常用于此的一种解决方案是在非常小的数字( math.Abs(expected-result) < ɛ ,您定义 ɛ: const ɛ = 0.0000001 )内进行相等比较,而不是使用 == .

关于go - 略有不同的 float 学结果(C 到 golang),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32411643/

有关go - 略有不同的 float 学结果(C 到 golang)的更多相关文章

  1. 报告回顾丨模型进化狂飙,DetectGPT能否识别最新模型生成结果? - 2

    导读语言模型给我们的生产生活带来了极大便利,但同时不少人也利用他们从事作弊工作。如何规避这些难辨真伪的文字所产生的负面影响也成为一大难题。在3月9日智源Live第33期活动「DetectGPT:判断文本是否为机器生成的工具」中,主讲人Eric为我们讲解了DetectGPT工作背后的思路——一种基于概率曲率检测的用于检测模型生成文本的工具,它可以帮助我们更好地分辨文章的来源和可信度,对保护信息真实、防止欺诈等方面具有重要意义。本次报告主要围绕其功能,实现和效果等展开。(文末点击“阅读原文”,查看活动回放。)Ericmitchell斯坦福大学计算机系四年级博士生,由ChelseaFinn和Chri

  2. java - 为什么 ruby​​ modulo 与 java/other lang 不同? - 2

    我基本上来自Java背景并且努力理解Ruby中的模运算。(5%3)(-5%3)(5%-3)(-5%-3)Java中的上述操作产生,2个-22个-2但在Ruby中,相同的表达式会产生21个-1-2.Ruby在逻辑上有多擅长这个?模块操作在Ruby中是如何实现的?如果将同一个操作定义为一个web服务,两个服务如何匹配逻辑。 最佳答案 在Java中,模运算的结果与被除数的符号相同。在Ruby中,它与除数的符号相同。remainder()在Ruby中与被除数的符号相同。您可能还想引用modulooperation.

  3. ruby-on-rails - 在 RSpec 中,如何以任意顺序期望具有不同参数的多条消息? - 2

    RSpec似乎按顺序匹配方法接收的消息。我不确定如何使以下代码工作:allow(a).toreceive(:f)expect(a).toreceive(:f).with(2)a.f(1)a.f(2)a.f(3)我问的原因是a.f的一些调用是由我的代码的上层控制的,所以我不能对这些方法调用添加期望。 最佳答案 RSpecspy是测试这种情况的一种方式。要监视一个方法,用allowstub,除了方法名称之外没有任何约束,调用该方法,然后expect确切的方法调用。例如:allow(a).toreceive(:f)a.f(2)a.f(1)

  4. ruby-on-rails - 如何用不同的用户运行nginx主进程 - 2

    A/ctohttp://wiki.nginx.org/CoreModule#usermaster进程曾经以root用户运行,是否可以以不同的用户运行nginxmaster进程? 最佳答案 只需以非root身份运行init脚本(即/etc/init.d/nginxstart),就可以用不同的用户运行nginxmaster进程。如果这真的是你想要做的,你将需要确保日志和pid目录(通常是/var/log/nginx&/var/run/nginx.pid)对该用户是可写的,并且您所有的listen调用都是针对大于1024的端口(因为绑定(

  5. ruby - 从 sinatra 中的 before do block 返回不同的值 - 2

    有没有办法在sinatra的beforedoblock中停止执行并返回不同的值?beforedo#codeishere#Iwouldliketo'return"Message"'#Iwouldlike"/home"tonotgetcalled.end//restofthecodeget'/home'doend 最佳答案 beforedohalt401,{'Content-Type'=>'text/plain'},'Message!'end如果你愿意,你可以只指定状态,这里有状态、标题和正文的例子

  6. ruby-on-rails - Sunspot:如何对具有不同值的多个字段进行全文查询? - 2

    我想用sunspot重现以下原始solr查询q=exact_term_text:fooORterm_textv:foo*ORalternate_text:bar*但我无法通过标准的太阳黑子界面理解这是否可能以及如何实现,因为看起来:fulltext方法似乎不接受多个文本/搜索字段参数我不知道将什么参数作为第一个参数传递给fulltext,就好像我通过了"foo"或"bar"结果不匹配如果我传递一个空参数,我得到一个q=*:*范围过滤器(例如with(:term).starting_with('foo*')(顾名思义)作为过滤器查询应用,因此不参与评分。似乎可以手动编写字符串(或者可能使

  7. ruby - 拆分字符串并分配给不同的变量 - 2

    我从ui中得到日期范围为-approved_between"=>"2013-03-17-2013-03-18"我需要拆分此approved_start_date="2013-03-17"和approved_end_date="2013-03-18"...我希望使用它在mysql中查询,因为mysql中的日期格式是created_at:2012-07-2810:35:01.我正在做的是:approved=approved_between.split("")approved_start_date=approved[0]approved_end_date=approved[2]很确定这不是处

  8. ruby - 如果散列有 key ,则使用它。否则,使用不同的 key - 2

    response是一个散列,可能看起来像以下两种情况之一:response={'demo'=>'nil','test_01'=>'DemoData'}或response={'test'=>'DemoData','demo'=>'nil'}我想做这样的事情:ifresponse.has_key?'test_01'new_response.update(:nps_score=>response['test_01']elsenew_response.update(:nps_score=>response['test']end是否有更“Ruby”的方法来解决这个问题?也许使用||的东西运算符(

  9. ruby-on-rails - 32651 :ERROR comparison of Float with Float failed ruby - 2

    我是Rails的新手,我遇到了一个错误,但我似乎找不到问题所在。这是日志:[32651:ERROR]2012-10-0913:46:52::comparisonofFloatwithFloatfailed[32651:ERROR]2012-10-0913:46:52::/home/sunny/backend/lib/analytics/lifetime.rb:45:in`each'/home/sunny/backend/lib/analytics/lifetime.rb:45:in`max'/home/sunny/backend/lib/analytics/lifetime.rb:45

  10. ruby - 为什么在 Ruby 中是 Float::INFINITY == Float::INFINITY? - 2

    在数学中,2个无穷大既不等于,也不大于或小于then。那么是什么给了?在irb中,Float::INFINITY==Float::INFINITY(在ruby​​1.9.3中测试) 最佳答案 用更专业的术语来说,这一切都归结为浮点运算的IEEE754标准。TheIEEE754standarddoesimplicitlydefineInfinity==Infinitytobetrue.Therelevantpartofthestandardissection5.7:"Fourmutuallyexclusiverelationsarep

随机推荐