float64 precision

polaris · · 662 次点击    
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
<p>Sorry, this feels like something really simple that I&#39;m missing. And it is something that happens in other languages, like js... but it doesn&#39;t hurt to ask.</p> <p>So I have the following (I&#39;m adding 0.01 to a variable in a loop):</p> <p><a href="https://play.golang.org/p/E_VQv8U7ha" rel="nofollow">https://play.golang.org/p/E_VQv8U7ha</a></p> <p>I understand what is going on, there&#39;s a loss of precision, but how can I avoid it?</p> <p>EDIT: in golang we don&#39;t have a toFixed(). I managed to fix it but I was checking if you guys know what is the best way to solve this issue.</p> <p>Edit2: thank you guys for the answers. I ended up using David Calhoun&#39;s answer here: <a href="http://stackoverflow.com/questions/18390266/how-can-we-truncate-float64-type-to-a-particular-precision-in-golang" rel="nofollow">http://stackoverflow.com/questions/18390266/how-can-we-truncate-float64-type-to-a-particular-precision-in-golang</a></p> <hr/>**评论:**<br/><br/>FIuffyRabbit: <pre><p>Because it isn&#39;t a language problem but a problem with how floats are represented in general.</p> <p><a href="https://stackoverflow.com/questions/21895756/why-are-floating-point-numbers-inaccurate" rel="nofollow">https://stackoverflow.com/questions/21895756/why-are-floating-point-numbers-inaccurate</a></p></pre>sickntwisted: <pre><p>I know. that&#39;s why I gave the example of js as well. I&#39;ve just never had to deal with it before and now I did.</p></pre>joncalhoun: <pre><p>The best solution often depends on the context. Why do you need two points of fixed precision?</p> <p>If you are dealing with currency (like USD), often the easiest solution is to convert your data to cents - <code>1.01</code> becomes <code>101</code>, and you can now store it in an integer. Stripe and others do this when dealing with currency values as you only need two points of precision.</p> <p>Another option is to try to determine how much precision you need. For example, if you only need <code>1e-9</code> precision you can probably just use floating points and write your code like this: <a href="https://play.golang.org/p/55sWUBov2o" rel="nofollow">https://play.golang.org/p/55sWUBov2o</a></p> <p>This will make sure your for loop continues to run until x is at least <code>1e-9</code> greater than <code>1.4</code>. This method takes a bit more practice to know when to use it, but it can be useful at times.</p></pre>sickntwisted: <pre><p>You are right. I would never think of your solutions because I work with ABAP. This floating point drifting doesn&#39;t happen there.</p> <p>Lately I&#39;ve been trying some personal programming projects as hobbies, more to gain more knowledge than anything else, and go has been one of the languages I&#39;ve tried. But I really need to get out of the ABAP mindframe.</p></pre>barsonme: <pre><p>if you need decimal numbers: <a href="https://GitHub.com/ericlagergren/decimal" rel="nofollow">https://GitHub.com/ericlagergren/decimal</a></p></pre>sickntwisted: <pre><p>ok! this is good. :) </p> <p>thanks a lot for this. I really need to explore the available libraries more.</p></pre>tmornini: <pre><p>Right answer, every time!</p></pre>hobbified: <pre><p>Avoid it in what fashion? In this case the simplest thing you could do would be to count by 1s instead of by .01, and divide by 100 for display purposes instead of letting your intermediate values be lossy — but what&#39;s your overall goal?</p></pre>sickntwisted: <pre><p>My goal is to have a map of values for statistical analysis. I could also use strings for this purpose. And yes, using integers and then dividing for the display is a good way of achieving this. thanks.</p> <p>My problem was that I was a bit more ahead in my program and I was comparing 1.15 with the value calculated and it was always returning false. That&#39;s when I decided to print those values and understood that 1.15 was never there...</p></pre>radovskyb: <pre><p>Are you trying to avoid just giving them set precisions?</p> <p>For example: <a href="https://play.golang.org/p/07WUGY6RHo" rel="nofollow">https://play.golang.org/p/07WUGY6RHo</a> or <a href="https://play.golang.org/p/IKsts4I5Yc" rel="nofollow">https://play.golang.org/p/IKsts4I5Yc</a></p></pre>sickntwisted: <pre><p>what you are printing is different from the real value. the 1.03 you are printing is, in reality, 1.03000000001 and that is the value that gets used in subsequent operations.</p></pre>tscs37: <pre><p>Floating Point numbers have some imprecision.</p> <p>You can either use one of the methods here to work around the imprecision or alternatively you can use a Decimal library.</p> <p>If the problem is not related to science or machine learning, you might want to consider decimal numbers.</p> <p>Lastly, you can always just multiply until you can represent the numbers as integers.</p></pre>chewxy: <pre><p>The best way to compare floats is to actually wrote a function that looks like this:</p> <pre><code>func tolerance (a, b, e float64) { d := a - b if d &lt; 0 { d = -d } if b != 0 { e = e * b if e &lt; 0 { e = -e } } return d &lt; e } </code></pre> <p>For really close tolerance use 4e-16. For close tolerance use e = 1e-14. For most general cases, 1e-8 is more than enough</p></pre>dasacc22: <pre><p>Does that do something this doesn&#39;t? Was hard to follow.</p> <pre><code>const epsilon = 1e-4 func equals(a, b float64) bool { return equaleps(a, b, epsilon) } func equaleps(a, b float64, eps float64) bool { return (a-b) &lt; eps &amp;&amp; (b-a) &lt; eps } </code></pre></pre>dasacc22: <pre><p>If speed isn&#39;t critical, check out math/big <a href="https://golang.org/pkg/math/big/" rel="nofollow">https://golang.org/pkg/math/big/</a></p></pre>chewxy: <pre><p>The best way to compare floats is to actually write a function that looks like this:</p> <pre><code>func tolerance (a, b, e float64) { d := a - b if d &lt; 0 { d = -d } if b != 0 { e = e * b if e &lt; 0 { e = -e } } return d &lt; e } </code></pre> <p>For really close tolerance use 4e-16. For close tolerance use e = 1e-14. For most general cases, 1e-8 is more than enough</p> <p>Source: I deal with a lot of float issues in machine learning</p></pre>

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

662 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传