二进制编码的十进制

本文介绍了计算机中的二进制编码十进制(BCD)及其在会计和数据库中的重要性。由于二进制舍入误差可能导致严重问题,BCD提供了一种精确的数值格式。文章探讨了BCD的历史,包括4GL编程语言、Borland C++编译器,以及整数编码和任意浮点数的实现。同时,它详细阐述了BCD数据类型,特别是与ODBC标准的兼容性,强调了BCD在数据库交互和性能测量中的优势。此外,文章还提供了一个测试项目,用于验证和比较BCD与其他数据类型的性能。
摘要由CSDN通过智能技术生成

介绍 (Introduction)

Computers calculate numbers in binary. We forget about this many times as the illusion of a mathematical machine is quite compelling. It’s far easier to forget about binary rounding errors and pretend that calculations are precise.

计算机以二进制形式计算数字。 我们忘记了很多次,因为数学机器的错觉非常引人注目。 忘记二进制舍入错误并假装计算是精确的,要容易得多。

Alas! This doesn’t add up for dull purposes like accounting and bookkeeping. Here, a roundoff error of 1 cent can sent an accountant screaming for an explanation and a multi-million dollar investigation. And it is for accounting reasons that databases have special datatypes like NUMERIC and DECIMAL that are precise number formats. This is in contrast with approximate data types like FLOAT and REAL.

唉! 这不会增加诸如会计和簿记等乏味的目的。 在这里,四舍五入的误差为1美分,可能会导致会计师大声疾呼,要求解释和进行数百万美元的调查。 出于会计原因,数据库具有特殊的数据类型,例如NUMERICDECIMAL ,它们是精确的数字格式。 这与诸如FLOATREAL近似数据类型形成对比。

In the C++ language, the built-in datatype “double” (IEEE 754) datatype is in radix 2, so it is also an approximate datatype. Although the Intel x386 processor has something of a ‘bcd’ type of operator to correct the effect of binary calculations, no C++ compiler today exists with a built-in exact numeric datatype. (Borland C++ 2.0 being the last one that had that!)

在C ++语言中,内置数据类型“ double ”(IEEE 754)数据类型位于基数2中,因此它也是一种近似datatype 。 尽管Intel x386处理器具有某种“ bcd ”类型的运算符来纠正二进制计算的影响,但如今不存在具有内置精确数值数据类型的C ++编译器。 (Borland C ++ 2.0是具有该功能的最后一个!)

The solution has been to store these numbers in the so-called “BINARY-CODED-DECIMAL” format. BCD for short. In such an implementation, no rounding errors can occur, as extra bits are used to represent a decimal number instead of a binary number.

解决方案是将这些数字以所谓的“ BINARY-CODED-DECIMAL”格式存储。 BCD的简称。 在这样的实现中,不会发生舍入错误,因为多余的位用于表示十进制数而不是二进制数。

This lack of a binary-coded-decimal datatype makes it cumbersome to do accounting and book­keeping calculations in C++. Also, the storing and retrieving of NUMERIC and DECIMAL numbers to and from databases require lengthy calculations to convert the numbers, requiring precious CPU cycles.

由于缺少二进制编码的十进制datatype ,因此在C ++中进行记帐和簿记计算很麻烦。 同样,在数据库中存储和检索NUMERICDECIMAL编号也需要很长的计算时间才能转换为数字,这需要宝贵的CPU周期。

ODBC案例 (The ODBC Case)

The ODBC (Open-DataBase Connectivity) standard has a data structure (SQL_NUMERIC_STRUCT) to transport the data for NUMERIC and DECIMAL numbers. Data for these datatypes is often binded and used in ODBC applications as a string. The binary transport of that data in a radix 256 numeric struct is often too great a challenge for most programmers on a daily business schedule.

ODBC(开放数据库连接)标准具有一个数据结构( SQL_NUMERIC_STRUCT ),用于传输NUMERICDECIMAL编号的数据。 这些datatype通常被绑定并在ODBC应用程序中用作string 。 以基数256的数字struct对数据进行二进制传输对于大多数程序员而言,在日常业务计划中通常是一个很大的挑战。

The chapter about “BCD and the ODBC Standard” explains how this bcd class solves that problem.

关于“ BCD和ODBC标准 ”的章节解释了该bcd类如何解决该问题。

BCD的前身 (Predecessors of BCD)

There have existed (and still exist!) a number of predecessors to this bcd class.

这个bcd类已经存在(并且仍然存在!)许多前辈。

4GL编程语言 (4GL Programming Languages)

Fourth generation languages bonded to a specific database platform (e.g., INFORMIX-4GL) had a DECIMAL datatype as a built-in feature. Binary coded decimal calculations were the default on this platform which made it typically suited to build accounting software and store the results in a database.

绑定到特定数据库平台的第四代语言(例如INFORMIX-4GL )具有DECIMAL数据类型作为内置功能。 二进制编码的十进制计算是该平台上的默认设置,这使其通常适合于构建会计软件并将结果存储在数据库中。

Borland C ++编译器 (The Borland C++ Compiler)

Upto the point where Borland sold their C++ compiler to Embarcadero, it had a built in ‘bcddatatype that could be directly used, just as you would use an ‘int’ or a ‘double’. To my best knowledge, this data­type was dropped in the later versions of this compiler.

直到Borland将其C ++编译器出售给Embarcadero为止,它都有一个内置的' bcd ' datatype可以直接使用,就像您使用' int '或' double '一样。 据我所知,此datatype已在此编译器的更高版本中删除。

Microsoft has never bundled a ‘bcddatatype with their implementation of the C++ language. And the language itself, not even through the process of the ISO standard, has ever featured such a datatype. So Borland was unique in this respect.

Microsoft从未将' bcd ' datatype与C ++语言的实现捆绑在一起。 语言本身甚至没有经过ISO标准的处理,就具有这种datatype 。 因此,Borland在这方面是独一无二的。

整数编码的十进制 (Integer-coded-decimal)

In order to do exact numerical calculations, my first try was to implement a numeric class that stores the numbers in integer format. 4 integers before the decimal point and 4 integers after the decimal point. This implementation – dubbed the integer-coded-decimal – did allow for 16 decimal places before and after the decimal point. Enough to do the bookkeeping of a large multi-national company or a small country. 😊

为了进行精确的数值计算,我的第一个尝试是实现一个数值类,以整数形式存储数字。 小数点前的4个整数,小数点后的4个整数。 此实现称为“整数编码的十进制”,确实允许在小数点之前和之后保留16个小数位。 足以完成大型跨国公司或小国的簿记工作。 😊

Although the classical operators like adding and subtracting are easy to implement in this format, much was left to be desired. As soon as we want to implement more mathematical operators, this implementation becomes bothersome, and as we will see later: slow.

尽管像加法和减法之类的经典运算符很容易以这种格式实现,但仍然有很多不足之处。 一旦我们想要实现更多的数学运算符,这种实现就会变得很麻烦,而且正如我们稍后将看到的:缓慢。

任意浮点 (Arbitrary-Floating-Point)

After some searching in the mathematical realm, I found the arbitrary-floating-point (AFP) class of Henrik Vestermark. This library takes the approach of storing the mathematical mantissa and the fractional part separately. The fractional part is stored in a character array, and interpreted in each mathematical operation. As such, it is an implementation of a precise binary-coded-decimal.

在数学领域中进行了一些搜索之后,我发现了Henrik Vestermark的任意浮点(AFP)类。 该库采用分开存储数学尾数和小数部分的方法。 小数部分存储在字符数组中,并在每个数学运算中进行解释。 这样,它是精确的二进制编码的十进制的实现。

The source code of this library is included in the BCD project. But see also the website of “Numerical Methods at Work” at http://hvks.com as this project has evolved since I took the idea from it.

该库的源代码包含在BCD项目中。 但也请访问http://hvks.com上的“工作中的数字方法”网站,因为自从我从中汲取灵感以来,该项目已经发展起来。

The downside of this library is (apart from performance problems) that the format is not easily transcoded to database formats like NUMERIC and DECIMAL.

该库的缺点是(除性能问题外)该格式不易转换为NUMERICDECIMAL类的数据库格式。

两全其美的 (The Best of Both Worlds)

Both methods (integer-coded-decimal and arbitrary-floating-point) have led the resulting design of the binary-coded-decimal class here presented. It stores the exponent and the mantissa separately. The mantissa however is stored as a set of integers. In the current configuration, 5 integers for 8 decimal positions each is used. Thus allowing for a mantissa of 40 positions. More than enough to even handle the most demanding database implementation (Oracle with 38 positions).

两种方法(整数编码的十进制和任意浮点数)都导​​致了此处介绍的二进制编码的十进制类的最终设计。 它分别存储指数和尾数。 但是,尾数存储为一组整数。 在当前配置中,使用8个小数位的5个整数。 因此允许40个位置的尾数。 甚至足以处理最苛刻的数据库实现(拥有38个职位的Oracle)。

Integers can hold at least 9 decimal places as a positive 32-bit “int” or “long” can hold up to the number of 2.147.483.647. This makes it possible to hold 8 decimal places and still have one digit left to hold any carry or borrow number when iterating over and array of these integers.

整数可以保留至少9个小数位,因为32位正数“ int ”或“ long ”最多可以容纳2.147.483.647 。 这样就可以保留8个小数位,并且在遍历这些整数和数组时仍可保留一位数字以保留任何进位或借位数字。

BCD数据类型 (The BCD Datatype)

The BCD (Binary-Coded-Decimal) datatype was built with database numeric and decimal datatypes in mind. A binary-coded-decimal number is an EXACT number with no rounding errors due to the binary nature of a computer CPU (Central Processing Unit). This makes the bcd datatype especially suited for financial and bookkeeping purposes.

BCD(二进制编码十进制)数据类型是在考虑数据库数字和十进制数据类型的情况下构建的。 二进制编码的十进制数是由于计算机CPU(中央处理单元)的二进制性质而没有舍入错误的精确数字。 这使得bcd数据类型特别适合于财务和簿记目的。

BCD calculations have been present in computer science for quite some time, and in various forms. This BCD class was especially designed to co-exist with ODBC database adapters. For more information, see the chapter “BCD and the ODBC Standard”.

BCD计算已经在计算机科学中存在了很长一段时间,并且形式多样。 该BCD类专门设计用于与ODBC数据库适配器共存。 有关更多信息,请参见“ BCD和ODBC标准 ”一章。

构建和初始化 (Construction and Initialization)

You can construct a bcd from just about every base C++ datatype, while initializing the bcd at the same time. This goes for chars, integers, longs, 64bit-integers, floats and doubles.

您可以从几乎所有基本C ++数据类型构造bcd,同时同时初始化bcd。 这适用于字符,整数,长整数,64位整数,浮点数和双精度数。

// Made from an integer and a floating point number
bcd num1(2);
bcd num2(4.0);
bcd num3 = num1 + num2;  // will become 6

But also for strings and from other bcd number.

而且还适用于string s和其他bcd编号。

// Made from a string and a different bcd number
bcd num4("7.25");
bcd num5(num3);
bcd num6 = num4 + num5;  // will become 13.5

Here is a complete list of all constructor types:

这是所有构造函数类型的完整列表:

  • The default constructor (initializes the number to zero (‘0.0’))

    默认构造函数(将数字初始化为零('0.0'))
  • Constructed from a char number (-127 to +127)

    从字符数构造(从-127到+127)
  • Constructed from an unsigned char number (0 upto 255)

    从无符号字符数(0到255)构造
  • Constructed from a short (-32767 upto 32767)

    从短构造(从-32767到32767)
  • Constructed from an unsigned short (0 upto 65535)

    由无符号的short构造(0到65535)
  • Constructed from an integer (-2147483647 upto 2147483647)

    从整数构造(-2147483647至2147483647)
  • Constructed from an unsigned integer (0 upto 4294967295)

    从无符号整数构造(0到4294967295)
  • Constructed from a 64bits integer (-9223372036854775807 upto 9223372036854775807)

    从64位整数构造(-9223372036854775807至9223372036854775807)
  • Constructed from an unsigned 64bits integer (0 upto 18446744073709551615)

    由无符号64位整数(0到18446744073709551615)构造
  • Constructed from another bcd

    从另一个bcd构造
  • Constructed from a string of type CString (MFC)

    从类型为CString (MFC)的string构造

  • Constructed from a string of type “const char *

    从类型为“ const char * ”的string构造

  • Constructed from a SQL_NUMERIC_STRUCT (as appearing in the ODBC standard)

    SQL_NUMERIC_STRUCT构造(如ODBC标准中所示)

常数 (Constants)

There are three defined constants in the bcd datatype. These constants are:

bcd datatype定义了三个常量。 这些常量是:

  • PI: The well known circle/radius ratio

    PI :众所周知的圆/半径比

  • LN2: The natural logarithm of 2

    LN2 :2的自然对数

  • LN10: The logarithm of 10

    LN10 :10的对数

They appear as “const bcd” numbers and can be used as such. Here are a few simple examples to show their use.

它们显示为“ const bcd ”数字,因此可以使用。 这里有一些简单的例子来说明它们的用法。

// Numbers made up with the help of constants
bcd ratio = 2 * PI();
bcd quart = bcd::PI() / bcd(2);

作业 (Assignments)

Other bcds, integers, doubles and strings can be assigned to a bcd number. That is: you can use the standard ‘=’ assignment operator or the operators that are combined with the standard mathematical operations ‘+=’, ‘-=’, ‘*=’, ‘/=’ and ‘%=’. Assignment operators made of a combination with bitwise operators like ‘|=’ or ‘&=’ have no logical counterpart in the bcd class, as a bitwise operation has no logical meaning for a binary coded decimal number.

可以将其他bcd,整数,双精度数和字符串分配给bcd号码。 也就是说:您可以使用标准的'='赋值运算符或与标准数学运算符'+ =','-=','* =','/ ='和'%='结合使用的运算符。 与“ | =”或“&=”之类的按位运算符组合而成的赋值运算符在bcd类中没有逻辑对应项,因为按位运算对二进制编码的十进制数没有逻辑含义。

// Calculation with assignments
bcd a = SomeFunc();
a += 2;
a *= b;    // a = b + (2 * SomeFunc)

增量和减量 (Increments and Decrements)

Both prefix and postfix increments and decrements can be used with a bcd just as with any integer number.

前缀和后缀的增量和减量都可以与bcd一起使用,就像与任何整数一样。

// Calculation with prefix and postfix in- and decrements
bcd a = ++b;
bcd c = a--;

经营者 (Operators)

The standard mathematical operators ‘+’ (addition), ‘-‘ (subtraction), ‘*’ (multiplication), ‘/’ (division) and ‘%’ (modulo) are implemented for the bcd class.

bcd类实现了标准数学运算符'+'(加法),'-'(减法),'*'(乘法),'/'(除法)和'%'(模)。

As this class is designed to do bookkeeping, it is the ‘bread-and-butter’ of this class. More than eighty percent of all calculations are done in these operators in real-world applications.

由于本课程旨在进行簿记,因此它是本课程的“头等大事”。 超过80%的计算是在实际应用中的这些运算符中完成的。

Here is a typical example:

这是一个典型的例子:

// Finding an average price from a std::vector of objects
// Where GetPrice() and GetVAT() both return a bcd value
bcd total;
for(auto& obj : objectlist)
{
   total += obj.GetPrice() + obj.GetVAT();
}
bcd average = total / (int)objectlist.count();
if(average > 400.0)
{
  ReportAverageToHigh(average);
}

比较 (Comparisons)

All typical comparison operators like equal (==), not-equal (!=), smaller (<), smaller-than-or-equal-to (<=), greater (>) and greater-than-or-equal-to (>=) are implemented for the bcd class.

所有典型的比较运算符,例如等于(==),不等于(!=),较小(<),小于等于(<=),大于(>)和大于等于-to(> =)为bcd类实现。

For an example, see the previous paragraph where we report an average that is too high.

例如,请参见上一段,其中我们报告的平均值过高。

数学函数 (Mathematical Functions)

The C library contains a number of mathematical functions that are solely implemented in the ‘double’ basic datatype. An example of these is, e.g., “pow” for the taking of a power. These functions are implemented as statistical functions with bcds as parameters. Static mathematical functions include:

C库包含许多仅在' double '基本datatype实现的数学函数。 这些的一个例子是,例如,用于取得权力的“ pow ”。 这些函数被实现为以bcd为参数的统计函数。 静态数学函数包括:

Apart from the static functions, they are also implemented as methods of the bcd class. So “pow” has a symmetrical method ‘Power’.

static函数外,它们还作为bcd类的方法实现。 因此,“ pow ”具有对称的“ Power ”方法。

Image 1

Here are two examples that do exactly the same:

这是两个完全相同的示例:

// Calculate the side of a square
bcd surface = GetSquareSurfaceArea();
bcd side = surface.SquareRoot();

and:

和:

// Calculate the side of a square
bcd surface = GetSquareSurfaceArea();
bcd side = sqrt(surface);

NOTE: Overloading the mathematical functions make is meant to make it easier to port existing code with doubles to be converted into bcds.

注意 :重载数学函数make的目的是使移植带有double s的现有代码更容易,以将其转换为bcd s。

三角函数 (Trigonometric Functions)

The standard C trigonometric functions are overloaded for the bcd class as is the case with the standard mathematical functions. Just as with the standard trigonometric functions, the number is an angle measured in radians. The following functions exist:

标准C三角函数对于bcd类是重载的,就像标准数学函数一样。 就像标准三角函数一样,数字是一个以弧度为单位的角度。 存在以下功能:

Image 2

Here are two examples that do exactly the same:

这是两个完全相同的示例:

// Calculate the height of a given wave
bcd waveHeight = GetSignal().Sine();

and:

和:

// Calculate the height of a given wave
bcd waveHeight = sin(GetSignal());

转换次数 (Conversions)

It is possible to convert a bcd to ‘something-else’. This other ‘something’ is a base datatype from the C++ language. Most methods are named something like “AsXXXX”, where XXXX denotes the type we want. The following methods exist:

可以将bcd转换为“ something-else”。 其他“内容”是C ++语言的基本数据类型。 大多数方法的名称都类似于“ AsXXXX ”,其中XXXX表示我们想要的类型。 存在以下方法:

Image 3

Here is an example of a calculation returning an engineering number string in 10 exponential format.

这是一个以10指数格式返回工程编号string的计算示例。

// Return a calculation in a IEEE number string
CString GetCalculation()
{
  bcd number1 = SomeFunction();
  bcd number2 = AnotherFunction();
  bcd number3 = number1.Power(number2);

  // Something like "5.6773E-03"
  return number3.AsString(Engineering,false);
}

字符串显示 (String Display)

Numbers can be displayed as strings. How they are displayed depends on the application we are using the number in. This can be quite different for a scientific or engineering application in contrast to a bookkeeping application. The differences are loosely defined as:

数字可以显示为string s。 如何显示它们取决于我们在其中使用数字的应用程序。与簿记应用程序相比,对于科学或工程应用程序,这可能会大不相同。 差异大致定义为:

  1. n bookkeeping applications, we tend to display numbers with one decimal marker and as much thousand parts markers as needed. We display decimal places upto a defined amount and round of the rest of the decimal places;

    在簿记应用程序中,我们倾向于显示带有一个小数点标记和需要的千位标记的数字。 我们将显示小数位数(最多定义的数量),并显示其余的小数位数;
  2. In engineering applications, we tend to print the exact number just with one decimal marker. If the number gets to great (or to small) we shift to exponential display in powers of ten.

    在工程应用中,我们倾向于只用一个小数点标记打印出准确的数字。 如果数字变大(或变小),我们将以十次幂转换为指数显示。
  3. In both cases, we always print a negative number with a negative sign (-), but we can choose to print the positive sign (+) as well;

    在这两种情况下,我们总是打印带有负号(-)的负号,但是我们也可以选择打印带有正号(+)的负号;
  4. The decimal and thousand markers are defined by the current system local of the machine and thus the language the desktop is currently using.

    小数点和千位标记由计算机的当前系统本地定义,因此由桌面当前使用的语言定义。

Here are a few examples of both ways of displaying a number:

以下是两种显示数字的方式的示例:

Image 4

文件读写 (File Reading and Writing)

Applications might need to write information to a binary file. So there are two methods for integration with binary files. The first (WriteToFile(FILE*)) writes the bcd number to a file. The second (ReadFromFile(FILE*)) reads the bcd number back from that file. All primary factual information of the bcd number is stored.

应用程序可能需要将信息写入二进制文件。 因此,有两种与二进制文件集成的方法。 第一个( WriteToFile(FILE*) )将bcd编号写入文件。 第二个( ReadFromFile(FILE*) )从该文件中读取bcd编号。 存储了bcd编号的所有主要事实信息。

Any disturbance in the force (oh sorry: the file) will lead to an error, meaning the whole number gets stored or read back, or an error occurs. See the implementation for more details about the storing format of the bcd.

力的任何干扰(抱歉:文件)都将导致错误,这意味着整数会被存储或读回,或者发生错误。 有关bcd的存储格式的更多详细信息,请参见实现。

Storage and retrieval of the bcd number in the file is also network independent and little-big-endian independent, meaning you can store and retrieve the number in a portable way.

文件中的bcd编号的存储和检索也与网络无关,并且与little-big-endian无关,这意味着您可以通过便携式方式存储和检索该bcd编号。

信息及其他方法 (Information and Other Methods)

A number of methods exist that have not yet been discussed. The give information of some property of the bcd number or do a basic operation. Here is the remainder list:

存在许多尚未讨论的方法。 提供bcd编号某些属性的信息或执行基本操作。 以下是剩余清单:

Image 5

错误处理 (Error Handling)

Error handling is done by throwing a StdException. This exception is integrated with the MS-Windows C++ Safe Exception Handling in such a way that critical errors like null-pointer references and division-by-zero errors do **NOT** get a different exception handling – stopping the application, e.g., – but are integrated in the exception throwing.

通过抛出StdException来完成错误处理。 该异常与MS-Windows C ++安全异常处理集成在一起,使得诸如null指针引用和零除错误之类的严重错误确实无法获得不同的异常处理–停止应用程序,例如, –但已集成到异常抛出中。

Here is a list of all errors in the bcd class. There descriptions are meant to be self-explanatory:

这是bcd类中所有错误的列表。 这里的描述是不言自明的:

Image 6

增强和完善 (Enhancements and Refinements)

The bcd class can easily be enhanced. You can simply expand the number of digits in the mantissa by using a greater number on integers in the mantissa array. See the constants “bcdDigits” and “bcdLength” at the beginning of the class interface definition.

bcd类可以轻松增强。 您可以通过在尾数数组中的整数上使用更大的数字来简单地扩展尾数中的位数。 请参见类接口定义开头的常量“ bcdDigits ”和“ bcdLength ”。

Extra methods and / or data, operators, stream interfaces like std::iostream can easily be added to this class.

可以轻松地将额外的方法和/或数据,运算符,流接口(如std::iostream添加到此类。

The bcd project comes with a unit test module DLL. The goal of the unit test is, of course, to test the correct workings of the other functionality while you expand the class.

bcd项目带有一个单元测试模块DLL。 当然,单元测试的目标是在扩展类时测试其他功能的正确运行。

Just open the test explorer in Visual Studio (from the menu “Test” / “Run all tests”) and check that all unit test are ‘in-the-green’.

只需在Visual Studio中打开测试资源管理器(从菜单“ 测试 ” /“ 运行所有测试 ”),并检查所有单元测试是否为“绿色”。

Image 7

BCD和ODBC标准 (BCD and the ODBC Standard)

Now with the mathematical calculations firmly in place, we can turn to the usage of the bcd number in combination with the ODBC drivers. Binary data flows to and from the ODBC driver of a database in the form of the SQL_NUMERIC_STRUCT. This struct supports both the NUMERIC and DECIMAL datatypes of a modern ISO:9075 compliant SQL database.

现在已经有了正确的数学计算,我们可以将bcd编号与ODBC驱动程序结合使用。 二进制数据以SQL_NUMERIC_STRUCT的形式流入和流出数据库的ODBC驱动程序。 该struct支持现代ISO:9075兼容SQL数据库的NUMERICDECIMAL datatype

Binding directly to a DECIMAL or NUMERIC column in a database query will result in the retrieval of a SQL_NUMERIC_STRUCT in memory. Changing and using that struct in an update or insert statement will use the contents of that struct and transport it to our database record.

直接绑定到数据库查询中的DECIMALNUMERIC列将导致在内存中检索SQL_NUMERIC_STRUCT 。 在updateinsert语句中更改并使用该struct将使用该struct的内容并将其传输到我们的数据库记录中。

But what happens when we get that data. Peeking at the source code of some open-source database implementations like the MySql, MariaDB, Firebird or PostgreSQL reveals that most odbc drivers just convert a string to a SQL_NUMERIC_STRUCT. At the moment that this dataclass was written, those conversions were quite complicated, long and error prone. In the last years, the situation has improved, but…

但是,当我们获得这些数据时会发生什么。 偷看MySql,MariaDB,Firebird或PostgreSQL等一些开源数据库实现的源代码,发现大多数odbc驱动程序只是将string转换为SQL_NUMERIC_STRUCT 。 在编写此dataclass的那一刻,这些转换非常复杂,冗长且容易出错。 在过去的几年中,情况有所改善,但是…

  1. This conversion only converts the standard number format with a decimal point. No exponential numbers can be converted.

    此转换仅转换带小数点的标准数字格式。 不能转换指数数。
  2. A lot of confusion still exists in the usage of NUMERIC and DECIMAL. Looking up answers on the stackoverflow platform, even experienced programmers opt-in to let the database convert the data to a string and plucking that string data out of the query.

    NUMERICDECIMAL的用法仍然存在很多困惑。 在stackoverflow平台上查找答案时,甚至有经验的程序员都选择让数据库将数据转换为字符串并将该string数据从查询中删除。

The BCD class has been designed to easily convert to and from the SQL_NUMERIC_STRUCT. With the following two methods:

BCD类被设计为可以轻松地与SQL_NUMERIC_STRUCT转换。 用以下两种方法:

  • bcd::SetValueNumeric(SQL_NUMERIC_STRUCT*);

    bcd::SetValueNumeric(SQL_NUMERIC_STRUCT*);

  • bcd::AsNumeric(SQL_NUMERIC_STRUCT*);

    bcd::AsNumeric(SQL_NUMERIC_STRUCT*);

Data is directly converted to and from the ODBC bind area and to the database. These conversions are a simple iteration over the mantissa and copy of the mantissa and sign bit.

数据直接与ODBC绑定区域和数据库之间进行转换。 这些转换是对尾数以及尾数和符号位的副本进行的简单迭代。

主要优势 (The Main Advantage)

The key factor here is that we can directly use our NUMERIC and DECIMAL numbers without having them to convert first to a string and back to a format where we can begin calculations in them. Round-about the other direction: we can directly calculate and store the result in the database without having to convert everything to strings and order the database to convert it back to exactly the same data again!

这里的关键因素是我们可以直接使用我们的NUMERICDECIMAL数字,而无需先将它们转换为string然后再转换为可以在其中开始计算的格式。 绕过另一个方向:我们可以直接计算结果并将其存储在数据库中,而不必将所有内容都转换为string s,并且可以命令数据库再次将其转换回完全相同的数据!

SQL组件 (SQLComponents)

The main application of the bcd class lies within the SQLComponents library. This is a library around the ODBC driver. You can find this library at https://github.com/edwig/SQLComponents.

bcd类的主要应用程序位于SQLComponents库中。 这是一个围绕ODBC驱动程序的库。 您可以在https://github.com/edwig/SQLComponents中找到该库。

In this library, all datarows are bound to a SQLRecord object. The columns of each record in turn are bound to the SQLVariant class.

在此库中,所有datarow均绑定到SQLRecord对象。 每个记录的列又绑定到SQLVariant类。

The SQLVariant class acts as a sorts of variable placeholder for all datatypes that can be obtained from a database row. And of course: one of the datatypes is the bcd class.

SQLVariant类充当可从数据库行获取的所有datatype的变量占位符。 当然: datatype s之一是bcd类。

The SQLComponents database makes it easier to program with any given ODBC driver. It has been tested with Oracle, MS-SQLServer, MySQL, PostgreSQL, MS-Access and IBM-Informix.

SQLComponents数据库使使用任何给定的ODBC驱动程序编程变得更加容易。 它已经过Oracle,MS-SQLServer,MySQL,PostgreSQL,MS-Access和IBM-Informix的测试。

打开ODBCQuerytool (The Open ODBCQuerytool)

Apart from a number of business applications, the one and only killer-app that’s using the SQLComponents and bcd class is the Open ODBC-Querytool. You can find this querytool through github on: https://github.com/edwig/ODBCQueryTool and on sourceforge under the following link: https://sourceforge.net/projects/odbcquerytool/. From this last link, it has seen more than 50.000 downloads in the last years.

除了许多业务应用程序之外,使用SQLComponents和bcd类的唯一且唯一的杀手级应用程序是Open ODBC-Querytool。 您可以通过以下网址的 github找到此查询工具: https : //github.com/edwig/ODBCQueryTool以及sourceforge下的以下链接: https ://sourceforge.net/projects/odbcquerytool/。 从最后一个链接看,最近几年下载量已超过50.000。

绩效评估 (Performance Measuring)

In order to be able to measure the performance of my implementations, I designed a test program that does any number of calculations a configurable number of times ‘n’. When setting ‘n’ to for instance a 1000 times, the length of the calculations will be great enough to be able to measure it with a high performance counter like “QueryPerformanceCounter” of the MS-Windows kernel.

为了能够衡量我的实现的性能,我设计了一个测试程序,该程序可以按可配置的次数“ n ”进行任意数量的计算。 当将“ n ”设置为例如1000倍时,计算长度将足够大,从而能够使用诸如MS-Windows内核的“ QueryPerformanceCounter ”之类的高性能计数器进行测量。

The test program compares the result of each operation with the result of the MS-Windows desktop calculator “calc.exe” and shows the performance results of four implementations:

测试程序将每个操作的结果与MS-Windows桌面计算器“ calc.exe ”的结果进行比较,并显示四种实现的性能结果:

  1. C++ built-in “double

    C ++内置“ double

  2. Arbitrary-floating-point

    任意浮点
  3. Integer-coded-decimal

    整数编码的十进制
  4. Binary-coded-decimal

    二进制编码的十进制

A typical output of the test program looks like:

测试程序的典型输出如下所示:

Testing the function [log10] for a total of [1000] iterations:

Input: 98765432109876543210.123456789012345678901234567890

Type         Time Value
------ ---------- ------------------------------------------------------
calc     0.000000 +19.994604968162151965673558368195
double   0.000005 +19.994604968162150
afp      0.982142 +19.99460496816215196567355836819543212297
icd      0.191501 +19.9946049681621519656735583681954349795885
bcd      0.050899 +19.9946049681621519656735583681954321229

In this example, we see the results for the “log10” function (logarithm in base 10). As we can see, the result is correct upto at least 32 decimal places for each implementation (apart from ‘double’ ☹)

在此示例中,我们看到“ log10 ”函数的结果(以10为底的对数)。 如我们所见,对于每个实现,结果至少在小数点后32位都是正确的(除了'double'☹)

A thousand iterations take 0,05 seconds in the bcd implementation: 50 microseconds each. Quite a bit longer than the 50 nanoseconds for a double calculation. But at a far greater precision!

在bcd实现中,一千次迭代需要0.05秒:每次50微秒。 重复计算的时间比50纳秒长一点。 但是精度更高!

The BCD solution in the example program runs this test by default.

示例程序中的BCD解决方案默认运行此测试。

This is a screenshot of the beginning of the testrun:

这是测试运行开始的屏幕截图:

Image 8

And here is a sample of the output at the end of the testrun:

这是测试运行结束时的输出示例:

Image 9

In a test run in the mode of 1000 iterations on a modern Intel Core i7-7700K CPU with an ASUS Z270 motherboard we can now compare the timings of all mathematical functions. Here is a typical end result, shown in a table:

现在,在带有ASUS Z270主板的现代Intel Core i7-7700K CPU上以1000次迭代的模式进行测试,我们现在可以比较所有数学函数的时序。 下表显示了典型的最终结果:

图片10
()

结论 (Conclusion)

From the performance table above it’s clear that the best performance is of course the built-in double datatype. But that’s with rounding errors and all. From the other solutions (straight 8 bits BCD by the AFP solutiohn, the integer-coded-decimal and the bcd-class) the bcd is the winner in all categories of calculations but one (addition). In those cases where bcd has the highest performance it can be from a few percent upto a staggering factor of 20 or 50 times faster or even higher.

从上面的性能表可以明显看出,最佳性能当然是内置的double数据类型。 但这就是四舍五入的错误。 从其他解决方案(AFP解决方案使用直8位BCD,整数编码的十进制和bcd类)中,bcd在所有计算类别中都是赢家,但一个(加法)则是赢家。 在bcd的性能最高的情况下,其速度可能从百分之几提高到惊人的20或50倍甚至更高。

Github (Github)

This project is also to be found on: https://github.com/edwig/bcd.

您也可以在以下位置找到该项目: https : //github.com/edwig/bcd

翻译自: https://www.codeproject.com/Articles/5254478/Binary-Coded-Decimal

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值