Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
M
MariaDB
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
nexedi
MariaDB
Commits
0b7f26d7
Commit
0b7f26d7
authored
Oct 19, 2004
by
serg@serg.mylan
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
decimal to/from bin, and utility functions
parent
5fd2c489
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
314 additions
and
29 deletions
+314
-29
include/decimal.h
include/decimal.h
+24
-15
strings/Makefile.am
strings/Makefile.am
+4
-5
strings/decimal.c
strings/decimal.c
+286
-9
No files found.
include/decimal.h
View file @
0b7f26d7
...
...
@@ -18,19 +18,17 @@
#define _decimal_h
#include <my_global.h>
#include <m_ctype.h>
#include <my_sys.h>
/* for my_alloca */
typedef
enum
{
TRUNCATE
=
0
,
EVEN
}
dec_round_mode
;
typedef
u
int32
decimal_digit
;
typedef
int32
decimal_digit
;
typedef
struct
st_decimal
{
int
intg
,
frac
,
len
;
int
intg
,
frac
,
len
;
my_bool
sign
;
decimal_digit
*
buf
;
}
decimal
;
int
decimal2string
(
decimal
*
from
,
char
*
to
,
u
int
*
to_len
);
int
decimal2string
(
decimal
*
from
,
char
*
to
,
int
*
to_len
);
int
string2decimal
(
char
*
from
,
decimal
*
to
,
char
**
end
);
int
decimal2ulonglong
(
decimal
*
from
,
ulonglong
*
to
);
int
ulonglong2decimal
(
ulonglong
from
,
decimal
*
to
);
...
...
@@ -38,31 +36,42 @@ int decimal2longlong(decimal *from, longlong *to);
int
longlong2decimal
(
longlong
from
,
decimal
*
to
);
int
decimal2double
(
decimal
*
from
,
double
*
to
);
int
double2decimal
(
double
from
,
decimal
*
to
);
int
decimal2bin
(
decimal
*
from
,
char
*
to
,
int
precision
,
int
scale
);
int
bin2decimal
(
char
*
from
,
decimal
*
to
,
int
precision
,
int
scale
);
int
decimal_size
(
int
precision
,
int
scale
);
int
decimal_bin_size
(
int
precision
,
int
scale
);
int
decimal_result_size
(
decimal
*
from1
,
decimal
*
from2
,
char
op
,
int
param
);
int
decimal_add
(
decimal
*
from1
,
decimal
*
from2
,
decimal
*
to
);
int
decimal_sub
(
decimal
*
from1
,
decimal
*
from2
,
decimal
*
to
);
int
decimal_mul
(
decimal
*
from1
,
decimal
*
from2
,
decimal
*
to
);
int
decimal_div
(
decimal
*
from1
,
decimal
*
from2
,
decimal
*
to
,
int
scale_incr
);
int
decimal_mod
(
decimal
*
from1
,
decimal
*
from2
,
decimal
*
to
);
int
decimal_result_size
(
decimal
*
from1
,
decimal
*
from2
,
char
op
,
int
param
);
int
decimal_round
(
decimal
*
dec
,
int
new_scale
,
dec_round_mode
mode
);
/*
the following works only on special "zero" decimal, not on any
decimal that happen to evaluate to zero
*/
#define decimal_is_zero(dec) ((dec)->intg1==1 && (dec)->frac1==0 && (dec)->buf[0]==0)
/*
conventions:
decimal_smth() == 0 -- everything's ok
decimal_smth() <=
0 -- result is usable,
precision loss is possible
decimal_smth() <=
1 -- result is unusable, but
most significant digits
c
an be
lost
decimal_smth() >
1
-- no result was generated
decimal_smth() <=
1 -- result is usable, but
precision loss is possible
decimal_smth() <=
2 -- result can be unusable,
most significant digits
c
ould've been
lost
decimal_smth() >
2
-- no result was generated
*/
#define E_DEC_TRUNCATED -1
#define E_DEC_OK 0
#define E_DEC_OVERFLOW 1
#define E_DEC_DIV_ZERO 2
#define E_DEC_BAD_NUM 3
#define E_DEC_OOM 4
#define E_DEC_TRUNCATED 1
#define E_DEC_OVERFLOW 2
#define E_DEC_DIV_ZERO 3
#define E_DEC_BAD_NUM 4
#define E_DEC_OOM 5
#endif
strings/Makefile.am
View file @
0b7f26d7
...
...
@@ -74,14 +74,13 @@ if ASSEMBLER
endif
FLAGS
=
$(DEFS)
$(INCLUDES)
$(CPPFLAGS)
$(CFLAGS)
@NOINST_LDFLAGS@
LIBS
=
libmystrings.a
str_test
:
str_test.c $(LIBRARIES)
$(LINK)
$(FLAGS)
-DMAIN
$(INCLUDES)
$(srcdir)
/str_test.c
$(LDADD)
$(
LIBS)
$(
pkglib_LIBRARIES)
str_test
:
str_test.c $(
pkglib_
LIBRARIES)
$(LINK)
$(FLAGS)
-DMAIN
$(INCLUDES)
$(srcdir)
/str_test.c
$(LDADD)
$(pkglib_LIBRARIES)
test_decimal$(EXEEXT)
:
decimal.c $(LIBRARIES)
test_decimal$(EXEEXT)
:
decimal.c $(
pkglib_
LIBRARIES)
$(CP)
$(srcdir)
/decimal.c ./test_decimal.c
$(LINK)
$(FLAGS)
-DMAIN
./test_decimal.c
$(LDADD)
$(
LIB
S)
$(LINK)
$(FLAGS)
-DMAIN
./test_decimal.c
$(LDADD)
$(
pkglib_LIBRARIE
S)
$(RM)
-f
./test_decimal.c
# Don't update the files from bitkeeper
...
...
strings/decimal.c
View file @
0b7f26d7
...
...
@@ -99,6 +99,9 @@
*/
#include <decimal.h>
#include <m_ctype.h>
#include <myisampack.h>
#include <my_sys.h>
/* for my_alloca */
typedef
decimal_digit
dec1
;
typedef
longlong
dec2
;
...
...
@@ -110,6 +113,7 @@ typedef longlong dec2;
#define ROUND_UP(X) (((X)+DIG_PER_DEC1-1)/DIG_PER_DEC1)
static
const
dec1
powers10
[
DIG_PER_DEC1
+
1
]
=
{
1
,
10
,
100
,
1000
,
10000
,
100000
,
1000000
,
10000000
,
100000000
,
1000000000
};
static
const
int
dig2bytes
[
DIG_PER_DEC1
+
1
]
=
{
0
,
1
,
1
,
2
,
2
,
3
,
3
,
3
,
4
,
4
};
#define FIX_INTG_FRAC_ERROR(len, intg1, frac1, error) \
do \
...
...
@@ -186,7 +190,7 @@ static const dec1 powers10[DIG_PER_DEC1+1]={
} while(0)
/*
Convert decimal to its string representation
Convert decimal to its
printable
string representation
SYNOPSIS
decimal2string()
...
...
@@ -199,7 +203,7 @@ static const dec1 powers10[DIG_PER_DEC1+1]={
E_DEC_OK/E_DEC_TRUNCATED/E_DEC_OVERFLOW
*/
int
decimal2string
(
decimal
*
from
,
char
*
to
,
u
int
*
to_len
)
int
decimal2string
(
decimal
*
from
,
char
*
to
,
int
*
to_len
)
{
int
len
,
intg
=
from
->
intg
,
frac
=
from
->
frac
,
i
;
int
error
=
E_DEC_OK
;
...
...
@@ -209,9 +213,11 @@ int decimal2string(decimal *from, char *to, uint *to_len)
DBUG_ASSERT
(
*
to_len
>
2
+
from
->
sign
);
/* removing leading zeroes */
i
=
intg
%
DIG_PER_DEC1
;
while
(
intg
>
0
&&
*
buf0
==
0
)
{
intg
-=
DIG_PER_DEC1
;
intg
-=
i
;
i
=
DIG_PER_DEC1
;
buf0
++
;
}
if
(
intg
>
0
)
...
...
@@ -231,7 +237,7 @@ int decimal2string(decimal *from, char *to, uint *to_len)
len
=
from
->
sign
+
intg
+
test
(
frac
)
+
frac
;
if
(
unlikely
(
len
>
--*
to_len
))
/* reserve one byte for \0 */
{
u
int
i
=
len
-*
to_len
;
int
i
=
len
-*
to_len
;
error
=
(
frac
&&
i
<=
frac
+
1
)
?
E_DEC_TRUNCATED
:
E_DEC_OVERFLOW
;
if
(
frac
&&
i
>=
frac
+
1
)
i
--
;
if
(
i
>
frac
)
...
...
@@ -517,6 +523,244 @@ int decimal2longlong(decimal *from, longlong *to)
return
from
->
frac
?
E_DEC_TRUNCATED
:
E_DEC_OK
;
}
/*
Convert decimal to its binary fixed-length representation
two representations of the same length can be compared with memcmp
with the correct -1/0/+1 result
SYNOPSIS
decimal2bin()
from - value to convert
to - points to buffer where string representation should be stored
precision/scale - see decimal_bin_size() below
NOTE
the buffer is assumed to be of the size decimal_bin_size(precision, scale)
RETURN VALUE
E_DEC_OK/E_DEC_TRUNCATED/E_DEC_OVERFLOW
*/
int
decimal2bin
(
decimal
*
from
,
char
*
to
,
int
precision
,
int
frac
)
{
dec1
mask
=
from
->
sign
?
-
1
:
0
,
*
buf1
=
from
->
buf
,
*
stop1
;
int
error
=
E_DEC_OK
,
intg
=
precision
-
frac
,
intg0
=
intg
/
DIG_PER_DEC1
,
frac0
=
frac
/
DIG_PER_DEC1
,
intg0x
=
intg
-
intg0
*
DIG_PER_DEC1
,
frac0x
=
frac
-
frac0
*
DIG_PER_DEC1
,
intg1
=
from
->
intg
/
DIG_PER_DEC1
,
frac1
=
from
->
frac
/
DIG_PER_DEC1
,
intg1x
=
from
->
intg
-
intg1
*
DIG_PER_DEC1
,
frac1x
=
from
->
frac
-
frac1
*
DIG_PER_DEC1
,
isize0
=
intg0
*
sizeof
(
dec1
)
+
dig2bytes
[
intg0x
],
fsize0
=
frac0
*
sizeof
(
dec1
)
+
dig2bytes
[
frac0x
],
isize1
=
intg1
*
sizeof
(
dec1
)
+
dig2bytes
[
intg1x
],
fsize1
=
frac1
*
sizeof
(
dec1
)
+
dig2bytes
[
frac1x
];
if
(
isize0
<
isize1
)
{
buf1
+=
intg1
-
intg0
+
(
intg1x
>
0
)
-
(
intg0x
>
0
);
intg1
=
intg0
;
intg1x
=
intg0x
;
error
=
E_DEC_OVERFLOW
;
}
else
if
(
isize0
>
isize1
)
{
while
(
isize0
--
>
isize1
)
*
to
++=
(
char
)
mask
;
}
if
(
fsize0
<
fsize1
)
{
frac1
=
frac0
;
frac1x
=
frac0x
;
error
=
E_DEC_TRUNCATED
;
}
else
if
(
fsize0
>
fsize1
&&
frac1x
)
{
if
(
frac0
==
frac1
)
frac1x
=
frac0x
;
else
{
frac1
++
;
frac1x
=
0
;
}
}
/* intg1x part */
if
(
intg1x
)
{
int
i
=
dig2bytes
[
intg1x
];
dec1
x
=
(
*
buf1
++
%
powers10
[
intg1x
])
^
mask
;
switch
(
i
)
{
case
1
:
mi_int1store
(
to
,
x
);
break
;
case
2
:
mi_int2store
(
to
,
x
);
break
;
case
3
:
mi_int3store
(
to
,
x
);
break
;
case
4
:
mi_int4store
(
to
,
x
);
break
;
default:
DBUG_ASSERT
(
0
);
}
to
+=
i
;
}
/* intg1+frac1 part */
for
(
stop1
=
buf1
+
intg1
+
frac1
;
buf1
<
stop1
;
to
+=
sizeof
(
dec1
))
{
dec1
x
=*
buf1
++
^
mask
;
DBUG_ASSERT
(
sizeof
(
dec1
)
==
4
);
mi_int4store
(
to
,
x
);
}
/* frac1x part */
if
(
frac1x
)
{
int
i
=
dig2bytes
[
frac1x
];
dec1
x
=
(
*
buf1
/
powers10
[
DIG_PER_DEC1
-
frac1x
])
^
mask
;
switch
(
i
)
{
case
1
:
mi_int1store
(
to
,
x
);
break
;
case
2
:
mi_int2store
(
to
,
x
);
break
;
case
3
:
mi_int3store
(
to
,
x
);
break
;
case
4
:
mi_int4store
(
to
,
x
);
break
;
default:
DBUG_ASSERT
(
0
);
}
to
+=
i
;
}
if
(
fsize0
>
fsize1
)
{
while
(
fsize0
--
>
fsize1
)
*
to
++=
(
uchar
)
mask
;
}
return
error
;
}
/*
Restores decimal from its binary fixed-length representation
SYNOPSIS
bin2decimal()
from - value to convert
to - result
precision/scale - see decimal_bin_size() below
NOTE
see decimal2bin()
the buffer is assumed to be of the size decimal_bin_size(precision, scale)
RETURN VALUE
E_DEC_OK/E_DEC_TRUNCATED/E_DEC_OVERFLOW
*/
int
bin2decimal
(
char
*
from
,
decimal
*
to
,
int
precision
,
int
scale
)
{
int
error
=
E_DEC_OK
,
intg
=
precision
-
scale
,
intg0
=
intg
/
DIG_PER_DEC1
,
frac0
=
scale
/
DIG_PER_DEC1
,
intg0x
=
intg
-
intg0
*
DIG_PER_DEC1
,
frac0x
=
scale
-
frac0
*
DIG_PER_DEC1
,
intg1
=
intg0
+
(
intg0x
>
0
),
frac1
=
frac0
+
(
frac0x
>
0
);
dec1
*
buf
=
to
->
buf
,
mask
=
(
*
from
<
0
)
?
-
1
:
0
;
char
*
stop
;
FIX_INTG_FRAC_ERROR
(
to
->
len
,
intg1
,
frac1
,
error
);
if
(
unlikely
(
error
))
{
if
(
intg1
<
intg0
+
(
intg0x
>
0
))
{
from
+=
dig2bytes
[
intg0x
]
+
sizeof
(
dec1
)
*
(
intg0
-
intg1
);
frac0
=
frac0x
=
intg0x
=
0
;
intg0
=
intg1
;
}
else
{
frac0x
=
0
;
frac0
=
frac1
;
}
}
to
->
sign
=
(
mask
!=
0
);
to
->
intg
=
intg0
*
DIG_PER_DEC1
+
intg0x
;
to
->
frac
=
frac0
*
DIG_PER_DEC1
+
frac0x
;
if
(
intg0x
)
{
int
i
=
dig2bytes
[
intg0x
];
dec1
x
;
switch
(
i
)
{
case
1
:
x
=
mi_sint1korr
(
from
);
break
;
case
2
:
x
=
mi_sint2korr
(
from
);
break
;
case
3
:
x
=
mi_sint3korr
(
from
);
break
;
case
4
:
x
=
mi_sint4korr
(
from
);
break
;
default:
DBUG_ASSERT
(
0
);
}
from
+=
i
;
*
buf
=
x
^
mask
;
if
(
buf
>
to
->
buf
||
*
buf
!=
0
)
buf
++
;
else
to
->
intg
-=
intg0x
;
}
for
(
stop
=
from
+
intg0
*
sizeof
(
dec1
);
from
<
stop
;
from
+=
sizeof
(
dec1
))
{
DBUG_ASSERT
(
sizeof
(
dec1
)
==
4
);
*
buf
=
mi_sint4korr
(
from
)
^
mask
;
if
(
buf
>
to
->
buf
||
*
buf
!=
0
)
buf
++
;
else
to
->
intg
-=
DIG_PER_DEC1
;
}
DBUG_ASSERT
(
to
->
intg
>=
0
);
for
(
stop
=
from
+
frac0
*
sizeof
(
dec1
);
from
<
stop
;
from
+=
sizeof
(
dec1
))
{
DBUG_ASSERT
(
sizeof
(
dec1
)
==
4
);
*
buf
=
mi_sint4korr
(
from
)
^
mask
;
buf
++
;
}
if
(
frac0x
)
{
int
i
=
dig2bytes
[
frac0x
];
dec1
x
;
switch
(
i
)
{
case
1
:
x
=
mi_sint1korr
(
from
);
break
;
case
2
:
x
=
mi_sint2korr
(
from
);
break
;
case
3
:
x
=
mi_sint3korr
(
from
);
break
;
case
4
:
x
=
mi_sint4korr
(
from
);
break
;
default:
DBUG_ASSERT
(
0
);
}
*
buf
=
(
x
^
mask
)
*
powers10
[
DIG_PER_DEC1
-
frac0x
];
buf
++
;
}
return
error
;
}
/*
Returns the size of array to hold a decimal with given precision and scale
RETURN VALUE
size in dec1
(multiply by sizeof(dec1) to get the size if bytes)
*/
int
decimal_size
(
int
precision
,
int
scale
)
{
DBUG_ASSERT
(
scale
>=
0
&&
precision
>
0
&&
scale
<=
precision
);
return
ROUND_UP
(
precision
-
scale
)
+
ROUND_UP
(
scale
);
}
/*
Returns the size of array to hold a binary representation of a decimal
RETURN VALUE
size in bytes
*/
int
decimal_bin_size
(
int
precision
,
int
scale
)
{
int
intg
=
precision
-
scale
,
intg0
=
intg
/
DIG_PER_DEC1
,
frac0
=
scale
/
DIG_PER_DEC1
,
intg0x
=
intg
-
intg0
*
DIG_PER_DEC1
,
frac0x
=
scale
-
frac0
*
DIG_PER_DEC1
;
DBUG_ASSERT
(
scale
>=
0
&&
precision
>
0
&&
scale
<=
precision
);
return
intg0
*
sizeof
(
dec1
)
+
dig2bytes
[
intg0x
]
+
frac0
*
sizeof
(
dec1
)
+
dig2bytes
[
frac0x
];
}
/*
Rounds the decimal to "scale" digits
...
...
@@ -538,7 +782,7 @@ int decimal2longlong(decimal *from, longlong *to)
int
decimal_round
(
decimal
*
dec
,
int
scale
,
dec_round_mode
mode
)
{
int
frac0
=
ROUND_UP
(
scale
),
frac1
=
ROUND_UP
(
dec
->
frac
),
intg0
=
ROUND_UP
(
dec
->
intg
),
error
=
E_DEC_OK
,
pos
,
len
=
dec
->
len
;
intg0
=
ROUND_UP
(
dec
->
intg
),
error
=
E_DEC_OK
,
len
=
dec
->
len
;
dec1
*
buf
=
dec
->
buf
,
x
,
y
,
carry
=
0
;
DBUG_ASSERT
(
intg0
+
frac1
<=
len
);
...
...
@@ -659,18 +903,19 @@ int decimal_result_size(decimal *from1, decimal *from2, char op, int param)
}
case
'*'
:
return
ROUND_UP
(
from1
->
intg
+
from2
->
intg
)
+
ROUND_UP
(
from1
->
frac
+
from2
->
frac
);
ROUND_UP
(
from1
->
frac
)
+
ROUND_UP
(
from2
->
frac
);
case
'/'
:
return
ROUND_UP
(
from1
->
intg
+
from2
->
intg
+
1
+
from1
->
frac
+
from2
->
frac
+
param
);
default:
DBUG_ASSERT
(
0
);
}
return
-
1
;
/* shut up the warning */
}
static
int
do_add
(
decimal
*
from1
,
decimal
*
from2
,
decimal
*
to
)
{
int
intg1
=
ROUND_UP
(
from1
->
intg
),
intg2
=
ROUND_UP
(
from2
->
intg
),
frac1
=
ROUND_UP
(
from1
->
frac
),
frac2
=
ROUND_UP
(
from2
->
frac
),
frac0
=
max
(
frac1
,
frac2
),
intg0
=
max
(
intg1
,
intg2
),
error
,
i
;
frac0
=
max
(
frac1
,
frac2
),
intg0
=
max
(
intg1
,
intg2
),
error
;
dec1
*
buf1
,
*
buf2
,
*
buf0
,
*
stop
,
*
stop2
,
x
,
carry
;
/* is there a need for extra word because of carry ? */
...
...
@@ -743,8 +988,8 @@ static int do_sub(decimal *from1, decimal *from2, decimal *to)
{
int
intg1
=
ROUND_UP
(
from1
->
intg
),
intg2
=
ROUND_UP
(
from2
->
intg
),
frac1
=
ROUND_UP
(
from1
->
frac
),
frac2
=
ROUND_UP
(
from2
->
frac
);
int
frac0
=
max
(
frac1
,
frac2
),
error
,
i
;
dec1
*
buf1
,
*
buf2
,
*
buf0
,
*
stop1
,
*
stop2
,
*
start1
,
*
start2
,
x
,
carry
=
0
;
int
frac0
=
max
(
frac1
,
frac2
),
error
;
dec1
*
buf1
,
*
buf2
,
*
buf0
,
*
stop1
,
*
stop2
,
*
start1
,
*
start2
,
carry
=
0
;
to
->
sign
=
from1
->
sign
;
...
...
@@ -1333,6 +1578,27 @@ void test_d2f(char *s)
printf
(
"%-40s => res=%d %.*g
\n
"
,
s1
,
res
,
a
.
intg
+
a
.
frac
,
x
);
}
void
test_d2b2d
(
char
*
str
,
int
p
,
int
s
)
{
char
s1
[
100
],
buf
[
100
];
double
x
;
int
res
,
i
,
size
=
decimal_bin_size
(
p
,
s
);
sprintf
(
s1
,
"'%s'"
,
str
);
string2decimal
(
str
,
&
a
,
0
);
res
=
decimal2bin
(
&
a
,
buf
,
p
,
s
);
printf
(
"%-31s {%2d, %2d} => res=%d size=%-2d "
,
s1
,
p
,
s
,
res
,
size
);
if
(
full
)
{
printf
(
"0x"
);
for
(
i
=
0
;
i
<
size
;
i
++
)
printf
(
"%02x"
,
((
uchar
*
)
buf
)[
i
]);
}
res
=
bin2decimal
(
buf
,
&
a
,
p
,
s
);
printf
(
" => res=%d "
,
res
);
print_decimal
(
&
a
);
printf
(
"
\n
"
);
}
void
test_f2d
(
double
from
)
{
int
res
;
...
...
@@ -1622,6 +1888,17 @@ main()
test_md
(
"-234.567"
,
"10.555"
);
test_md
(
"234.567"
,
"-10.555"
);
printf
(
"==== decimal2bin/bin2decimal ====
\n
"
);
test_d2b2d
(
"12345"
,
5
,
0
);
test_d2b2d
(
"12345"
,
10
,
3
);
test_d2b2d
(
"123.45"
,
10
,
3
);
test_d2b2d
(
"-123.45"
,
20
,
10
);
test_d2b2d
(
".00012345000098765"
,
15
,
14
);
test_d2b2d
(
".00012345000098765"
,
22
,
20
);
test_d2b2d
(
".12345000098765"
,
30
,
20
);
test_d2b2d
(
"-.000000012345000098765"
,
30
,
20
);
test_d2b2d
(
"1234500009876.5"
,
30
,
5
);
return
0
;
}
#endif
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment