关于Currency类型和 TCurrencyFiled的悲剧
这2天程序出问题, 用户结算金额经常莫名其妙的多出了小数点后几位, 不用思考 肯定是因为浮点精度不准确的问题
查了一下, 程序中的数据类型使用的是Currency, 按照数据类型的描述, 这个金额类型应该是以实数形式存储的, 完全不会出现精度不准确的问题, 那为什么现实中还是会有莫名其妙的小数出现呢
继续跟踪程序, 发现数据在中转过程中使用了内存表控件, 而金额数据对应的字段类型正好是TCurrencyFiled
写点测试代码, 发现每次从内存表字段存取数据, 就会出现数值误差, 难道是这个字段有问题?
跟踪进源码, 发现TCurrencyFiled是从TDoubleField字段上继承下来的, 莫非这个字段使用的是Double格式数据存储??!!
看一下Help, 然后悲剧的发现, 人家早就告诉你了:
TCurrencyField encapsulates the fundamental behavior common to currency fields. TCurrencyField differs from its immediate ancestor TFloatField only in having a DataType of ftCurrency, and in formatting the value using a currency format (one that represents monetary values) by default. Currency fields can hold values in the range from (positive or negative) 5.0 * 10^-324 to 1.7 * 10^308 with an accuracy of 15 digits. Do not confuse TCurrencyField with the Currency data type. Currency fields use the double data type to store and manipulate their values. This data type is the format used by the physical database tables for currency fields. The TBCDField class uses the Currency data type to store and manipulate its value. If you use the Fields editor at design time to create a persistent field component for the currency field, you can access it by name at runtime. When using dynamic field components, you can access the TCurrencyField instance using the dataset?
s Fields property or FieldByName method.
我嘞个擦.....Currency数据类型对应的居然不是TCurrencyField, 而应该是TBCDField......坑爹啊
最后补充一下: 一般我们常见的基本数据类型就不说了, 基本分为整型和浮点型, 其中整型是实数存储, 每个数据位都代表确切的数, 而浮点则是用指数存储, 表示成什么数完全取决于你要求的精度
所以...实数存储可以直接比较相等, 而指数一般无法比较(不是绝对不能比较)
这里最为特殊的, 就应该属于Currency类型了, 从数据表示上划分, 应该属于浮点类型数据, 因为他有小数, 而从存储形式上来看, 它又属于实数存储, 因为它的每个数据位都代表确切的值
如果还不明白, 可以使用下面的代码测试下:
var
i64: Int64;
c: Currency;
begin
i64 := ;
c := / ;
Move(c, i64, Sizeof(c));
ShowMessage(CurrToStr(c) + ## + IntToStr(i64));
end;
显示的结果是:
17.5714
175714
明白了吧, Currency实际上数据的存储和Int64是一样的, 只不过在使用的时候, 把最后4位认为是小数位而已
关于Currency类型和 TCurrencyFiled的悲剧的更多相关文章
- DATETIME类型和BIGINT 类型互相转换
项目中使用BIGINT来存放时间,以下代码用来转换时间类型和BIGINT类型 SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO -- ========= ...
- AngularJs:String类型和JSON相互转换
最近一周做了一个页面,制作的过程中遇到各种问题,从中可以看出本人的js基础还不够扎实,angularjs也只是刚入门的水平,现在将制作过程中遇到的问题一一汇总,方便以后查阅. 一.String类型和J ...
- Timestame类型和String 类型的转化
Timestame类型和String 类型的转化 String转化为Timestamp: SimpleDateFormat df = new SimpleDateFormat("yyyy-M ...
- Python3.x中bytes类型和str类型深入分析
Python 3最重要的新特性之一是对字符串和二进制数据流做了明确的区分.文本总是Unicode,由str类型表示,二进制数据则由bytes类型表示.Python 3不会以任意隐式的方式混用str和b ...
- Date类型和Long类型的相互转换
Date类型和Long类型的相互转换: import java.text.SimpleDateFormat; import java.util.Date; public class T { publi ...
- Java数据类型和MySql数据类型对应一览
类型名称 显示长度 数据库类型 JAVA类型 JDBC类型索引(int) 描述 VARCHAR L+N VARCHAR java.lang.String 12 CHAR N ...
- java中XMLGregorianCalendar类型和Date类型之间的相互转换
import java.text.SimpleDateFormat;import java.util.Date;import java.util.GregorianCalendar;import ja ...
- Java中int类型和tyte[]之间转换及byte[]合并
JAVA基于位移的 int类型和tyte[]之间转换 [java] view plaincopy /** * 基于位移的int转化成byte[] * @param int number * @retu ...
- 数据类型和typeof操作符
虽然学习js有一段时间了,但是对js的基础语法却是有些生疏.最近在看jquery源码,决定随带总结一些基础的语法知识.今天总结一下数据类型和typeof,这在写js的时候,是不得不知道的知识. 数据类 ...
随机推荐
- 每天一个linux命令---kill
linux中终止进程的命令--kill 一般用的是: 搜索pid: ps -ef|grep calendar 杀死pid:kill -9 pid 格式是:kill[参数][进程号]
- HDU2191(多重背包)
#include <cstdio> #include <cstring> #include <algorithm> #include <iostream> ...
- HD1847-(博弈论??)
Good Luck in CET-4 Everybody! Problem Description 大学英语四级考试就要来临了,你是不是在紧张的复习?也许紧张得连短学期的ACM都没工夫练习了,反正我知 ...
- The 2015 China Collegiate Programming Contest G. Ancient Go hdu 5546
Ancient Go Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 65535/65535 K (Java/Others)Total ...
- 如何真正提高ASP.NET网站的性能
摘要:前言 怎么才能让asp.net网站飞得更快,有更好的性能?这是很多开发者常常思考的一个问题.我有时候会做大量的测试,或请求别人帮忙采集一些数据,希望能够验证网上一些专家的建议或证明 前言 怎么才 ...
- Rock-Paper-Scissors Tournament[HDU1148]
Rock-Paper-Scissors TournamentTime Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Ja ...
- 【转】Android之自定义Adapter的ListView
http://www.cnblogs.com/topcoderliu/archive/2011/05/07/2039862.html 在开发中,我们经常使用到ListView这个控件.Android的 ...
- Android中使用Handler造成内存泄露
1.什么是内存泄露? Java使用有向图机制,通过GC自动检查内存中的对象(什么时候检查由虚拟机决定),如果GC发现一个或一组对象为不可到达状态,则将该对象从内存中回收.也就是说,一个对象不被任何引用 ...
- memcached 的安装与使用
准备条件:下载memcached的服务器端memcached-1.2.1.win32.zip(虽然最新版本已经是1. 4.6了,但win版本的好像还一直未更新,或找不到.) A.windows上的安装 ...
- python 获取进程pid号
#-*- encoding:UTF-8 -*- import os import sys import string import psutil import re def get_pid(name) ...