extjs的decimalprecision
js decimal方法

js decimal方法JS的decimal方法是一种用于处理十进制数的方法,它可以确保数值计算的准确性和精度。
在编程中,我们经常需要进行浮点数运算,但是由于浮点数的存储和运算方式的特殊性,会导致精度丢失和计算错误的问题。
而decimal方法可以解决这个问题,使我们能够更准确地进行数值计算。
我们需要了解一下浮点数的存储和运算原理。
在计算机中,浮点数采用二进制的科学计数法进行存储,即一个浮点数由符号位、指数位和尾数位组成。
在进行浮点数运算时,计算机会将两个浮点数进行对齐,并按照一定的规则进行运算。
然而,由于浮点数的精度有限,计算机在进行运算时会出现一定的误差。
这就是为什么在使用JS进行浮点数运算时,会出现精度丢失和计算错误的问题。
为了解决这个问题,JS提供了decimal方法。
它是一种用于处理十进制数的数据类型,可以确保数值计算的精度和准确性。
使用decimal方法,我们可以将浮点数转换为十进制数进行运算,从而避免精度丢失和计算错误的问题。
下面我们来看一个例子,假设我们需要计算两个浮点数相加的结果。
我们可以使用decimal方法将两个浮点数转换为十进制数,然后进行相加操作。
代码如下:```let num1 = 0.1;let num2 = 0.2;let sum = decimal(num1).add(decimal(num2));console.log(sum.toString());```在上面的代码中,我们首先定义了两个浮点数num1和num2,然后使用decimal方法将它们转换为十进制数。
接着,我们使用add 方法对这两个十进制数进行相加操作,得到了它们的和sum。
最后,我们使用toString方法将sum转换为字符串,并输出结果。
通过使用decimal方法,我们可以确保浮点数的计算结果准确无误。
这是因为decimal方法采用了一种精确的运算规则,可以避免浮点数运算中的精度丢失和计算错误。
extjsNumberField、隐藏字段Hidden、日期字段:DataFiedl]
![extjsNumberField、隐藏字段Hidden、日期字段:DataFiedl]](https://img.taocdn.com/s3/m/c44b7377bf23482fb4daa58da0116c175f0e1e91.png)
extjsNumberField、隐藏字段Hidden、日期字段:DataFiedl]//用户名input76var txtusername = new Ext.form.TextField({77 width: 140,78 allowBlank: false,79 maxLength: 20,80 name: 'username',81 fieldLabel: '用户名称',82 blankText: '请输入用户名',83 maxLengthText: '用户名不能超过20个字符'84 });85//密码input86var txtpassword = new Ext.form.TextField({87 width: 140,88 allowBlank: false,89 maxLength: 20,90 inputType: 'password',91 name: 'password',92 fieldLabel: '密码',93 blankText: '请输入密码',94 maxLengthText: '密码不能超过20个字符'95 });96//----------------------数字字段开始----------------------//97var numberfield = new Ext.form.NumberField({98 fieldLabel: '身高',99 width: 80,100 decimalPrecision: 1,101 minValue: 0.01,102 maxValue: 200,103 unitText: ' cm',104 allowBlank: false,105 blankText: '请输入身高'106 });107//----------------------数字字段结束----------------------//108//----------------------隐藏域字段开始----------------------//109var hiddenfield = new Ext.form.Hidden({110 name: 'userid',111 value: '1'112 });113//----------------------隐藏域字段结束----------------------//114//----------------------日期字段开始----------------------//115var datefield = new Ext.form.DateField({116 fieldLabel: '出生日期',117 format: 'Y-m-d',118 editable: false,119 allowBlank: false,120 blankText: '请选择日期'121 });122//----------------------日期字段结束----------------------//<!--152说明:153 (1)var numberfield = new Ext.form.NumberField():创建一个新的NumberField数字文本框对象。
extjs最常用的表单

Ext.form.TextArea多行文本域
替换html中的textarea组件 特殊配置项: preventScrollbars: boolean 文本内容溢出是 否显示滚动条 example22
常用配置项 autoCreate : String/Object //{tag: "textarea", style. "width:100px;height:60px;", autocomplete: "off"} growMax : Number //1000 growMin : Number //60 preventScrollbars : Boolean //如果为 真等于设置overflow: hidden,默认为false
Checkbox( Object config ) 构造,其中config{ autoCreate : String/Object, boxLabel : String, checked : Boolean, fieldClass : String,//x-form-field focusClass : String, } getValue() : Boolean initComponent() : void setValue( Boolean/String checked ) : void 事件 check : ( Ext.form.Checkbox this, Boolean checked )
regex : RegExp //正则匹配 regexText : String //提示 selectOnFocus : Boolean validator : Function //自定义验证方法,接受当前字段的值,如果合法,返回 真,反之返回自定义信息 vtype : String //Ext.form.VTypes 中定义的vtype类型名,支持简单的类型 验证 vtypeText : String//如果不是,则提示 常用方法 TextField( Object config )构造 autoSize() : void自动尺寸 reset() : void重置 selectText( [Number start], [Number end] ) : void选择文本 validateValue( Mixed value ield文本区
extjs numberfield 校验方法

extjs numberfield 校验方法校验方法是在开发过程中非常重要的一部分,它可以确保用户输入的数据符合预期的格式和规定。
对于使用ExtJS框架的开发者来说,ExtJS提供了丰富的校验方法,其中包括了NumberField控件的校验方法。
在本文中,我将逐步介绍如何使用ExtJS的校验方法来验证NumberField控件输入的数据。
1. 引入ExtJS框架首先,我们需要在项目中引入ExtJS框架。
可以通过在HTML文件中添加以下代码来实现:html<script src="<link rel="stylesheet" type="text/css" href="2. 创建NumberField控件接下来,我们需要创建一个NumberField控件,以便用户可以输入数字。
可以在ExtJS的Viewport中添加一个NumberField控件,代码如下:javascriptvar viewport = Ext.create('Ext.container.Viewport', {layout: 'fit',items: [{xtype: 'numberfield',fieldLabel: 'Number',id: 'numberField',allowBlank: false}]});在上述代码中,我们创建了一个带有标签名为"Number"的NumberField控件,并设置了必填项。
3. 添加校验方法现在,我们需要为NumberField控件添加校验方法。
可以通过在控件的`validator`属性中添加一个匿名函数,代码如下:javascript{xtype: 'numberfield',fieldLabel: 'Number',id: 'numberField',allowBlank: false,validator: function(value) {if (isNaN(value)) {return '请输入有效的数字';}return true;}}在上述代码中,我们通过`isNaN`函数来检查输入的值是否为有效的数字。
decimal.js简单用法

decimal.js简单用法1. 什么是decimal.js?decimal.js是一个用于处理精确小数运算的javascript库。
它可以有效地解决javascript本身对于小数运算的精度问题,提供了更加准确的数值计算能力。
decimal.js提供了一系列的方法和函数,可以用来进行小数的加减乘除、取余、四舍五入等操作,同时还支持设置精度、舍入模式等功能,方便开发者进行精确计算。
2. decimal.js的基本用法我们需要在项目中引入decimal.js库,并创建一个Decimal对象来进行计算。
接下来,我们可以使用Decimal对象提供的方法和属性来进行精确的小数运算。
下面是一些decimal.js的基本用法示例:```javascript// 引入decimal.js库const Decimal = require('decimal.js');// 创建Decimal对象const x = new Decimal('0.1');const y = new Decimal('0.2');// 加法const sum = x.plus(y);console.log(sum.toString()); // 输出0.3// 减法const difference = x.minus(y);console.log(difference.toString()); // 输出-0.1// 乘法const product = x.times(y);console.log(product.toString()); // 输出0.02// 除法const quotient = x.dividedBy(y);console.log(quotient.toString()); // 输出0.5```3. decimal.js的精度设置在实际应用中,我们经常需要设置小数的精度来满足具体的需求。
Extjs表单的数据校验

Extjs表单验证包括空验证、用vtype格式进行简单的验证、高级自定义密码验证、使用正则表达式验证等等。
验证可以使用js提供的脚本来进行代码编写,但ext本身对表单进行了封装,并允许客户对其进行扩展,因此使用Extjs提供的验证能够大大简化验证判断。
在验证之前,先看下面两个语句://放在onReady的function(){}中Ext.QuickTips.init(); //为组件提供提示信息功能,form的主要提示信息就是客户端验证的错误信息。
Ext.form.Field.prototype.msgTarget='side'; //提示的方式,枚举值为: qtip-当鼠标移动到控件上面时显示提示;title-在浏览器的标题显示,但是测试结果是和qtip一样的;under-在控件的底下显示错误提示;side-在控件右边显示一个错误图标,鼠标指向图标时显示错误提示. 默认值; id-[element id]错误提示显示在指定id的HTML元件中1.一个最简单的例子:空验证代码如下://空验证的两个参数allowBlank:false//false则不能为空,默认为trueblankText:string//当为空时的错误提示信息js代码为:代码如下:var form1 = new Ext.form.FormPanel({width:350,renderTo:"form1",title:"FormPanel",defaults:{xtype:"textfield",inputType:"password"},items:[{fieldLabel:"不能为空",allowBlank:false, //不允许为空blankText:"不能为空", //错误提示信息,默认为This field is required! id:"blanktest",}]});2.用vtype格式进行简单的验证。
decimal 长度和精度 定义

decimal 长度和精度定义
在计算机科学中,decimal(或称为十进制)是一种数
字系统,它使用十进制基数进行运算。
在许多编程语言中,如C#、Python等,都有对decimal的支持。
对于decimal,其长度和精度可以通过以下方式定义:
1.长度:表示一个十进制数可以表示的最大位数。
这通常由编程语言或数据库系统定义,而不是由用户直接指定。
例如,在C#中,decimal类型的长度是固定的,为128位。
2.精度:表示一个十进制数可以表示的有效数字的位数。
这通常包括小数点后的位数。
例如,在C#中,decimal类型的精度为34位。
注意,在定义decimal类型的数据时,编程语言可能会限制有效值的范围,以确保可以正确存储和操作所有数据。
超出此范围的值可能会引发错误或异常。
如果您在使用的特定编程语言或数据库系统中遇到问题,建议查阅相关文档以获取更详细的信息。
深入讲解数据库中Decimal类型的使用以及实现方法

深⼊讲解数据库中Decimal类型的使⽤以及实现⽅法⽬录1 背景2 Decimal类型的使⽤2.1 描述Decimal2.2 建表时定义Decimal2.3 写⼊decimal数据2.4 取出deimcal进⾏计算3 Decimal类型的实现3.1 MySQL3.2 ClickHouse3.3 总结4. MySQL 违反直觉的地⽅总结1 背景数字运算在数据库中是很常见的需求, 例如计算数量、重量、价格等, 为了满⾜各种需求, 数据库系统通常⽀持精准的数字类型和近似的数字类型. 精准的数字类型包含 int, decimal 等, 这些类型在计算过程中⼩数点位置是固定的, 其结果和⾏为⽐较可预测. 当涉及钱时, 这个问题尤其重要, 因此部分数据库实现了专门的 money 类型. 近似的数字类型包含 float, double 等, 这些数字的精度是浮动的.本⽂将简要介绍 decimal 类型的数据结构和计算, 对⽐ decimal 在 MySQL, ClickHouse 两个不同类型系统中的实现差异, 描述实现 decimal 运算的主要思路. MySQL 在结果的长度⽐较接近上限的情况下, 会有⽐较违反直觉的地⽅, 本⽂会在最后列出这些可能需要注意的问题.2 Decimal类型的使⽤decimal 的使⽤在多数数据库上都差不多, 下⾯以 MySQL 的 decimal 为例, 介绍 decimal 的基本使⽤⽅法.2.1 描述Decimal与 float 和 double 不同, decimal 在创建时需要指定两个描述精度的数字, 分别是 precision 和 scale, precision 指整个 decimal 包括整数和⼩数部分⼀共有多少个数字, scale 指 decimal 的⼩数部分包含多少个数字, 例如:123.45 就是⼀个 precision=5, scale=2 的 decimal. 我们可以在建表时按照这种⽅式定义我们想要的 decimal.2.2 建表时定义Decimal可以在建表时这样定义⼀个 decimal:create table t(d decimal(5, 2));2.3 写⼊decimal数据可以向其中插⼊合法的数据, 例如insert into t values(123.45);insert into t values(123.4);此时执⾏ select * from t 会得到+--------+| d |+--------+| 123.45 || 123.40 |+--------+注意到 123.4 变成了 123.40, 这就是精确类型的特点, d 列的每⾏数据都要求 scale=2, 即⼩数点后有两位当插⼊不满⾜ precision 和 scale 定义的数据时insert into t values(1123.45);ERROR 1264 (22003): Out of range value for column 'd' at row 1insert into t values(123.456);Query OK, 1 row affected, 1 warningshow warnings;+-------+------+----------------------------------------+| Level | Code | Message |+-------+------+----------------------------------------+| Note | 1265 | Data truncated for column 'd' at row 1 |+-------+------+----------------------------------------+select * from t;+--------+| d |+--------+| 123.46 |+--------+类似 1234.5 (precision=5, scale=1)这样的数字看起来满⾜要求, 但实际上需要满⾜ scale=2 的要求, 因此会变成1234.50(precision=6, scale=2) 也不满⾜要求.2.4 取出deimcal进⾏计算计算的结果不受定义的限制, ⽽是受到内部实现格式的影响, 对于 MySQL 结果最⼤可以到 precision=81, scale=30, 但是由于MySQL decimal 的内存格式和计算函数实现问题, 这个⼤⼩不是在所有情况都能达到, 将在后⽂中详细介绍. 继续上⾯的例⼦中:select d + 9999.999 from t;+--------------+| d + 9999.999 |+--------------+| 10123.459 |+--------------+结果突破了 precision=5, scale=2 的限制, 这⾥涉及运算时 scale 的变化, 基本规则是:1. 加法/减法/sum:取两边最⼤的 scale2. 乘法:两边的 scale 相加3. 除法:被除数的 scale + div_precision_increment(取决于数据库实现)3 Decimal类型的实现在这⼀部分中, 我们主要介绍 MySQL 的 decimal 实现, 此外也会对⽐ ClickHouse, 看看 decimal 在不同系统中的设计与实现差异.实现 decimal 需要思考以下问题1. ⽀持多⼤的 precision 和 scale2. 在哪⾥存储 scale3. 在连续乘法或除法时, scale 不断增长, 整数部分也不断扩⼤, ⽽存储的 buffer ⼤⼩总是有上限的, 此时应该如何处理?4. 除法可能产⽣⽆限⼩数, 如何决定除法结果的 scale?5. decimal 的表⽰范围和计算性能是否有冲突, 是否可以兼顾3.1 MySQL先来看看 MySQL decimal 相关的数据结构typedef int32 decimal_digit_t;struct decimal_t {int intg, frac, len;bool sign;decimal_digit_t *buf;};MySQL 的 decimal 使⽤⼀个长度为 len 的 decimal_digit_t (int32) 的数组 buf 来存储 decimal 的数字, 每个 decimal_digit_t 最多存储 9 个数字, ⽤ intg 表⽰整数部分的数字个数, frac 表⽰⼩数部分的数字个数, sign 表⽰符号. ⼩数部分和整数部分需要分开存储, 不能混合在⼀个 decimal_digit_t 中, 两部分都向⼩数点对齐, 这是因为整数和⼩数通常需要分开计算, 所以这样的格式可以更容易地将不同 decimal_t ⼩数和整数分别对齐, 便于加减法运算. len 在 MySQL 实现中恒为 9, 它表⽰存储的上限, ⽽ buf// 123.45 decimal(5, 2) 整数部分为 3, ⼩数部分为 2decimal_t dec_123_45 = {int intg = 3;int frac = 2;int len = 9;bool sign = false;decimal_digit_t *buf = {123, 450000000, ...};};MySQL 需要使⽤两个 decimal_digit_t (int32) 来存储 123.45, 其中第⼀个为 123, 结合 intg=3, 它就表⽰整数部分为 123, 第⼆个数字为 450000000 (共 9 个数字), 由于 frac=2, 它表⽰⼩数部分为 .45再来看⼀个⼤⼀点的例⼦:// decimal(81, 18) 63 个整数数字, 18 个⼩数数字, ⽤满整个 buffer// 123456789012345678901234567890123456789012345678901234567890123.012345678901234567decimal_t dec_81_digit = {int intg = 63;int frac = 18;int len = 9;bool sign = false;buf = {123456789, 12345678, 901234567, 890123456, 789012345, 678901234, 567890123, 12345678, 901234567}};这个例⼦⽤满了 81 个数字, 但是也有些场景⽆法⽤满 81 个数字, 这是因为整数和⼩数部分是分开存储的, 所以⼀个decimal_digit_t (int32) 可能只存储了⼀个有效的⼩数数字, 但是其余的部分没有办法给整数部分使⽤, 例如⼀个 decimal 整数部分有 62 个数字, ⼩数部分有 19 个数字(precision=81, scale=19), 那么⼩数部分需要使⽤ 3 个 decimal_digit_t (int32), 整数部分还有 54 个数字的余量, ⽆法存下 62 个数字. 这种情况下, MySQL 会优先满⾜整数部分的需求, ⾃动截断⼩数点后的部分, 将它变成 decimal(80, 18)接下来看看 MySQL 如何在这个数据结构上进⾏运算. MySQL 通过⼀系列 decimal_digit_t(int32) 来表⽰⼀个较⼤的 decimal,其计算也是对这个数组中的各个 decimal_digit_t 分别进⾏, 如同我们在⼩学数学计算时是⼀个数字⼀个数字地计算, MySQL 会把每个 decimal_digit_t 当作⼀个数字来进⾏计算、进位. 由于代码较长, 这⾥不再对具体的代码进⾏完整的分析, 仅对代码中核⼼部分进⾏分析, 如果感兴趣, 可以直接参考 MySQL 源码 strings/decimal.h 和 strings/ 中的 decimal_add, decimal_mul, decimal_div 等代码.准备步骤在真正计算前, 还需要做⼀些准备⼯作:1. MySQL 会将数字的个数 ROUND_UP 到 9 的整数倍, 这样后⾯就可以按照 decimal_digit_t 为单位来进⾏计算2. 此外还要针对参与运算的两个 decimal 的具体情况, 计算结果的 precision 和 scale, 如果发现结果的 precision 超过了⽀持的上限, 那么会按照 decimal_digit_t 为单位减少⼩数的数字.3. 在乘法过程中, 如果发⽣了 2 中的减少⾏为, 则需要 TRUNCATE 两个运算数, 避免中间结果超出范围.加法主要步骤⾸先, 因为两个数字的 precision 和 scale 可能不相同, 需要做⼀些准备⼯作, 将⼩数点对齐, 然后开始计算, 从最末尾⼩数开始向⾼位加, 分为三个步骤:1. 将⼩数较多的 decimal 多出的⼩数数字复制到结果中2. 将两个 decimal 公共的部分相加3. 将整数较多的 decimal 多出的整数数字与进位相加到结果中代码中使⽤了 stop, stop2 来标记⼩数点对齐后, 长度不同的数字出现差异的位置./* part 1 - max(frac) ... min (frac) */while (buf1 > stop) *--buf0 = *--buf1;/* part 2 - min(frac) ... min(intg) */carry = 0;while (buf1 > stop2) {ADD(*--buf0, *--buf1, *--buf2, carry);}/* part 3 - min(intg) ... max(intg) */buf1 = intg1 > intg2 ? ((stop3 = from1->buf) + intg1 - intg2): ((stop3 = from2->buf) + intg2 - intg1);while (buf1 > stop3) {ADD(*--buf0, *--buf1, 0, carry);乘法主要步骤乘法引⼊了⼀个新的 dec2, 表⽰⼀个 64 bit 的数字, 这是因为两个 decimal_digit_t(int32) 相乘后得到的可能会是⼀个 64 bit 的数字. 在计算时⼀定要先把类型转换到 dec2(int64), 再计算, 否则会得到溢出后的错误结果. 乘法与加法不同, 乘法不需要对齐,例如计算 11.11 5.0, 那么只要计算 111150=55550, 再移动⼩数点位置就能得到正确结果 55.550MySQL 实现了⼀个双重循环将 decimal1 的每⼀个 decimal_digit_t 与 decimal2 的每⼀个 decimal_digit_t 相乘, 得到⼀个 64位的 dec2, 其低 32 位是当前的结果, 其⾼ 32 位是进位.typedef decimal_digit_t dec1;typedef longlong dec2;for (buf1 += frac1 - 1; buf1 >= stop1; buf1--, start0--) {carry = 0;for (buf0 = start0, buf2 = start2; buf2 >= stop2; buf2--, buf0--) {dec1 hi, lo;dec2 p = ((dec2)*buf1) * ((dec2)*buf2);hi = (dec1)(p / DIG_BASE);lo = (dec1)(p - ((dec2)hi) * DIG_BASE);ADD2(*buf0, *buf0, lo, carry);carry += hi;}if (carry) {if (buf0 < to->buf) return E_DEC_OVERFLOW;ADD2(*buf0, *buf0, 0, carry);}for (buf0--; carry; buf0--) {if (buf0 < to->buf) return E_DEC_OVERFLOW;ADD(*buf0, *buf0, 0, carry);}}除法主要步骤除法使⽤的是 Knuth's Algorithm D, 其基本思路和⼿动除法也⽐较类似.⾸先使⽤除数的前两个 decimal_digit_t 组成⼀个试商因数, 这⾥使⽤了⼀个 norm_factor 来保证数字在不溢出的情况下尽可能扩⼤, 这是因为 decimal 为了保证精度必须使⽤整形来进⾏计算, 数字越⼤, 得到的结果就越准确. D3: 猜商, 就是⽤被除数的前两个 decimal_digit_t 除以试商因数这⾥如果不乘 norm_factor, 则 start1[1] 和 start2[1] 都不会体现在结果之中.D4: 将 guess 与除数相乘, 再从被除数中剪掉结果然后做⼀些修正, 移动向下⼀个 decimal_digit_t, 重复这个过程.norm2 = (dec1)(norm_factor * start2[0]);if (likely(len2 > 0)) norm2 += (dec1)(norm_factor * start2[1] / DIG_BASE);x = start1[0] + ((dec2)dcarry) * DIG_BASE;y = start1[1];guess = (norm_factor * x + norm_factor * y / DIG_BASE) / norm2;for (carry = 0; buf2 > start2; buf1--) {dec1 hi, lo;x = guess * (*--buf2);hi = (dec1)(x / DIG_BASE);lo = (dec1)(x - ((dec2)hi) * DIG_BASE);SUB2(*buf1, *buf1, lo, carry);carry += hi;}carry = dcarry < carry;3.2 ClickHouseClickHouse 是列存, 相同列的数据会放在⼀起, 因此计算时通常也将⼀列的数据合成 batch ⼀起计算.⼀列的 batch 在 ClickHouse 中使⽤ PODArray, 例如上图中的 c1 在计算时就会有⼀个 PODArray, 进⾏简化后⼤致可以表⽰如下:class PODArray {char * c_start = null;char * c_end = null;char * c_end_of_storage = null;在计算时会讲 c_start 指向的数组转换成实际的类型, 对于 decimal, ClickHouse 使⽤⾜够⼤的 int 来表⽰, 根据 decimal 的precision 选择 int32, int64 或者 int128. 例如⼀个 decimal(10, 2), 123.45, 使⽤这样⽅式可以表⽰为⼀个 int32_t, 其内容为12345, decimal(10, 3) 的 123.450 表⽰为 123450. ClickHouse ⽤来表⽰每个 decimal 的结构如下, 实际上就是⾜够⼤的 int:template <typename T>struct Decimal{using NativeType = T;// ...T value;};using Int32 = int32_t;using Int64 = int64_t;using Int128 = __int128;using Decimal32 = Decimal<Int32>;using Decimal64 = Decimal<Int64>;using Decimal128 = Decimal<Int128>;显⽽易见, 这样的表⽰⽅法相较于 MySQL 的⽅法更轻量, 但是范围更⼩, 同时也带来了⼀个问题是没有⼩数点的位置, 在进⾏加减法、⼤⼩⽐较等需要⼩数点对齐的场景下, ClickHouse 会在运算实际发⽣的时候将 scale 以参数的形式传⼊, 此时配合上⾯的数字就可以正确地还原出真实的 decimal 值了.ResultDataType type = decimalResultType(left, right, is_multiply, is_division);int scale_a = type.scaleFactorFor(left, is_multiply);int scale_b = type.scaleFactorFor(right, is_multiply || is_division);OpImpl::vector_vector(col_left->getData(), col_right->getData(), vec_res,scale_a, scale_b, check_decimal_overflow);例如两个 decimal: a = 123.45000(p=8, s=5), b = 123.4(p=4, s=1), 那么计算时传⼊的参数就是 col_left->getData() =123.45000 10 ^ 5 = 12345000, scale_a = 1, col_right->getData() = 123.4 10 ^ 1 = 1234, scale_b = 10000, 12345000 1 和1234 10000 的⼩数点位置是对齐的, 可以直接计算.加法主要步骤ClickHouse 实现加法同样要先对齐, 对齐的⽅法是将 scale 较⼩的数字乘上⼀个系数, 使两边的 scale 相等. 然后直接做加法即可. ClickHouse 在计算中也根据 decimal 的 precision 进⾏了细分, 对于长度没那么长的 decimal, 直接⽤ int32, int64 等原⽣类型计算就可以了, 这样⼤⼤提升了速度.bool overflow = false;if constexpr (scale_left)overflow |= common::mulOverflow(a, scale, a);elseoverflow |= common::mulOverflow(b, scale, b);overflow |= Op::template apply<NativeResultType>(a, b, res);template <typename T>inline bool addOverflow(T x, T y, T & res){return __builtin_add_overflow(x, y, &res);}template <>inline bool addOverflow(__int128 x, __int128 y, __int128 & res){static constexpr __int128 min_int128 = __int128(0x8000000000000000ll) << 64;static constexpr __int128 max_int128 = (__int128(0x7fffffffffffffffll) << 64) + 0xffffffffffffffffll;res = x + y;return (y > 0 && x > max_int128 - y) || (y < 0 && x < min_int128 - y);}乘法主要步骤同 MySQL, 乘法不需要对齐, 直接按整数相乘就可以了, ⽐较短的 decimal 同样可以使⽤ int32, int64 原⽣类型. int128 在溢出检测时被转换成 unsigned int128 避免溢出时的未定义⾏为.template <typename T>inline bool mulOverflow(T x, T y, T & res){return __builtin_mul_overflow(x, y, &res);}inline bool mulOverflow(__int128 x, __int128 y, __int128 & res){res = static_cast<unsigned __int128>(x) * static_cast<unsigned __int128>(y); /// Avoid signed integer overflow.if (!x || !y)return false;unsigned __int128 a = (x > 0) ? x : -x;unsigned __int128 b = (y > 0) ? y : -y;return (a * b) / b != a;}除法主要步骤先转换 scale 再直接做整数除法. 本⾝来讲除法和乘法⼀样是不需要对齐⼩数点的, 但是除法不⼀样的地⽅在于可能会产⽣⽆限⼩数, 所以⼀般数据库都会给结果⼀个固定的⼩数位数, ClickHouse 选择的⼩数位数是和被除数⼀样, 因此需要将 a 乘上 scale,然后在除法运算的过程中, 这个 scale 被⾃然减去, 得到结果的⼩数位数就可以保持和被除数⼀样.bool overflow = false;if constexpr (!IsDecimalNumber<A>)overflow |= common::mulOverflow(scale, scale, scale);overflow |= common::mulOverflow(a, scale, a);if (overflow)throw Exception("Decimal math overflow", ErrorCodes::DECIMAL_OVERFLOW);return Op::template apply<NativeResultType>(a, b);3.3 总结MySQL 通过⼀个 int32 的数组来表⽰⼀个⼤数, ClickHouse 则是尽可能使⽤原⽣类型, GCC 和 Clang 都⽀持 int128 扩展, 这使得 ClickHouse 的这种做法可以⽐较⽅便地实现.MySQL 与 ClickHouse 的实现差别还是⽐较⼤的, 针对我们开始提到的问题, 分别来看看他们的解答.1. precision 和 scale 范围, MySQL 最⾼可定义 precision=65, scale=30, 中间结果最多包含 81 个数字, ClickHouse 最⾼可定义 precision=38, scale=37, 中间结果最⼤为 int128 的最⼤值 -2^127 ~ 2^127-1.2. 在哪⾥存储 scale, MySQL 是⾏式存储, 使⽤⽕⼭模型逐⾏迭代, 计算也是按⾏进⾏, 每个 decimal 都有⾃⼰的 scale;ClickHouse 是列式存储, 计算按列批量进⾏, 每⾏按照相同的 scale 处理能提升性能, 因此 scale 来⾃表达式解析过程中推导出来的类型.3. scale 增长, scale 增长超过极限时, MySQL 会通过动态挤占⼩数空间, truncate 运算数, 尽可能保证计算完成, ClickHouse会直接报溢出错.4. 除法 scale, MySQL 通过 div_prec_increment 来控制除法结果的 scale, ClickHouse 固定使⽤被除数的 scale.5. 性能, MySQL 使⽤了更宽的 decimal 表⽰, 同时要进⾏ ROUND_UP, ⼩数挤占, TRUNCATE 等动作, 性能较差,ClickHouse 使⽤原⽣的数据类型和计算最⼤限度地提升了性能.4. MySQL 违反直觉的地⽅在这⼀部分中, 我们将讲述⼀些 MySQL 实现造成的违反直觉的地⽅. 这些⾏为通常发⽣在运算结果接近 81 digit 时, 因此如果可以保证运算结果的范围较⼩也可以忽略这些问题.1. 乘法的 scale 会截断到 31, 且该截断是通过截断运算数字的⽅式来实现的, 例如: select10000000000000000000000000000000.100000000 10000000000000000000000000000000 =10000000000000000000000000000000.10000000000000000000000000000010000000000000000000000000000000.555555555555555555555555555555 返回 1, 第⼆个运算数中的.555555555555555555555555555555 全部被截断2. MySQL 使⽤的 buffer 包含了 81 个 digit 的容量, 但是由于⼩数部分必须和整数部分分开, 因此很多时候⽆法⽤满 81 个digit, 例如: select99999999999999999999999999999999999999999999999999999999999999999999999999.999999 =99999999999999999999999999999999999999999999999999999999999999999999999999.9 返回 13. 计算过程中如果发现整数部分太⼤会动态地挤占⼩数部分, 例如: select999999999999999999999999999999999999999999999999999999999999999999999999.999999999 +999999999999999999999999999999999999999999999999999999999999999999999999.999999999 =999999999999999999999999999999999999999999999999999999999999999999999999 +999999999999999999999999999999999999999999999999999999999999999999999999 返回 14. 除法计算中间结果不受 scale = 31 的限制, 除法中间结果的 scale ⼀定是 9 的整数倍, 不能按照最终结果来推测除法作为中间结果的精度, 例如 select 2.0000 / 3 3 返回 2.00000000, ⽽ select 2.00000 / 3 3 返回 1.999999998, 可见前者除法的5. 除法, avg 计算最终结果的⼩数部分如果正好是 9 的倍数, 则不会四舍五⼊, 例如: select 2.00000 / 3 返回 0.666666666,select 2.0000 / 3 返回 0.666666676. 除法, avg 计算时, 运算数字的⼩数部分如果不是 9 的倍数, 那么会实际上存储 9 的倍数个⼩数数字, 因此会出现以下差异:create table t1 (a decimal(20, 2), b decimal(20, 2), c integer);insert into t1 values (100000.20, 1000000.10, 5);insert into t1 values (200000.20, 2000000.10, 2);insert into t1 values (300000.20, 3000000.10, 4);insert into t1 values (400000.20, 4000000.10, 6);insert into t1 values (500000.20, 5000000.10, 8);insert into t1 values (600000.20, 6000000.10, 9);insert into t1 values (700000.20, 7000000.10, 8);insert into t1 values (800000.20, 8000000.10, 7);insert into t1 values (900000.20, 9000000.10, 7);insert into t1 values (1000000.20, 10000000.10, 2);insert into t1 values (2000000.20, 20000000.10, 5);insert into t1 values (3000000.20, 30000000.10, 2);select sum(a+b), avg(c), sum(a+b) / avg(c) from t1;+--------------+--------+-------------------+| sum(a+b) | avg(c) | sum(a+b) / avg(c) |+--------------+--------+-------------------+| 115500003.60 | 5.4167 | 21323077.590317 |+--------------+--------+-------------------+1 row in set (0.01 sec)select 115500003.60 / 5.4167;+-----------------------+| 115500003.60 / 5.4167 |+-----------------------+| 21322946.369561 |+-----------------------+1 row in set (0.00 sec)总结到此这篇关于数据库中Decimal类型使⽤以及实现⽅法的⽂章就介绍到这了,更多相关Decimal类型使⽤及实现内容请搜索以前的⽂章或继续浏览下⾯的相关⽂章希望⼤家以后多多⽀持!。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
extjs的decimalprecision
在ExtJS中,decimalPrecision是一个属性,它用于指定在处理货币或小数时,应保留多少位小数。
ExtJS 是一个JavaScript 框架,用于创建丰富的、交互式的Web 应用程序。
它提供了许多工具和功能,以帮助开发人员更轻松地创建复杂的用户界面。
decimalPrecision属性通常在处理货币或小数时非常重要,因为它决定了显示和计算时的精度。
例如,如果你在银行应用程序中需要精确到小数点后两位,那么你可以将decimalPrecision设置为2。
需要注意的是,decimalPrecision属性通常与ExtJS中的其他属性(如fieldCls、fieldStyle等)一起使用,以控制输入字段的样式和行为。
总的来说,ExtJS中的decimalPrecision是指处理货币或小数时,应保留的小数位数。