Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wine-winehq
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
wine
wine-winehq
Commits
fa49ffcb
Commit
fa49ffcb
authored
Oct 26, 2005
by
Alex Villacís Lasso
Committed by
Alexandre Julliard
Oct 26, 2005
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Implement complete VarDecMul() for any valid DECIMAL.
parent
965a72ad
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
149 additions
and
31 deletions
+149
-31
vartype.c
dlls/oleaut32/vartype.c
+149
-31
No files found.
dlls/oleaut32/vartype.c
View file @
fa49ffcb
...
...
@@ -4615,6 +4615,25 @@ static void VARIANT_DIFromDec(const DECIMAL * from, VARIANT_DI * to)
to
->
bitsnum
[
2
]
=
DEC_HI32
(
from
);
}
static
void
VARIANT_DecFromDI
(
VARIANT_DI
*
from
,
DECIMAL
*
to
)
{
if
(
from
->
sign
)
{
DEC_SIGNSCALE
(
to
)
=
SIGNSCALE
(
DECIMAL_NEG
,
from
->
scale
);
}
else
{
DEC_SIGNSCALE
(
to
)
=
SIGNSCALE
(
DECIMAL_POS
,
from
->
scale
);
}
DEC_LO32
(
to
)
=
from
->
bitsnum
[
0
];
DEC_MID32
(
to
)
=
from
->
bitsnum
[
1
];
DEC_HI32
(
to
)
=
from
->
bitsnum
[
2
];
}
/* clear an internal representation of a DECIMAL */
static
void
VARIANT_DI_clear
(
VARIANT_DI
*
i
)
{
memset
(
i
,
0
,
sizeof
(
VARIANT_DI
));
}
/* divide the (unsigned) number stored in p (LSB) by a byte value (<= 0xff). Any nonzero
size is supported. The value in p is replaced by the quotient of the division, and
the remainder is returned as a result. This routine is most often used with a divisor
...
...
@@ -4651,6 +4670,103 @@ static int VARIANT_int_iszero(DWORD * p, unsigned int n)
return
1
;
}
/* multiply two DECIMALS, without changing either one, and place result in third
parameter. Result is normalized when scale is > 0. Attempts to remove significant
digits when scale > 0 in order to fit an overflowing result. Final overflow
flag is returned.
*/
static
int
VARIANT_DI_mul
(
VARIANT_DI
*
a
,
VARIANT_DI
*
b
,
VARIANT_DI
*
result
)
{
int
r_overflow
=
0
;
DWORD
running
[
6
];
signed
int
mulstart
;
VARIANT_DI_clear
(
result
);
result
->
sign
=
(
a
->
sign
^
b
->
sign
)
?
1
:
0
;
/* Multiply 128-bit operands into a (max) 256-bit result. The scale
of the result is formed by adding the scales of the operands.
*/
result
->
scale
=
a
->
scale
+
b
->
scale
;
memset
(
running
,
0
,
sizeof
(
running
));
/* count number of leading zero-bytes in operand A */
for
(
mulstart
=
sizeof
(
a
->
bitsnum
)
/
sizeof
(
DWORD
)
-
1
;
mulstart
>=
0
&&
!
a
->
bitsnum
[
mulstart
];
mulstart
--
);
if
(
mulstart
<
0
)
{
/* result is 0, because operand A is 0 */
result
->
scale
=
0
;
result
->
sign
=
0
;
}
else
{
unsigned
char
remainder
=
0
;
int
iA
;
/* perform actual multiplication */
for
(
iA
=
0
;
iA
<=
mulstart
;
iA
++
)
{
ULONG
iOverflowMul
;
int
iB
;
for
(
iOverflowMul
=
0
,
iB
=
0
;
iB
<
sizeof
(
b
->
bitsnum
)
/
sizeof
(
DWORD
);
iB
++
)
{
ULONG
iRV
;
int
iR
;
iRV
=
VARIANT_Mul
(
b
->
bitsnum
[
iB
],
a
->
bitsnum
[
iA
],
&
iOverflowMul
);
iR
=
iA
+
iB
;
do
{
running
[
iR
]
=
VARIANT_Add
(
running
[
iR
],
0
,
&
iRV
);
iR
++
;
}
while
(
iRV
);
}
}
/* Too bad - native oleaut does not do this, so we should not either */
#if 0
/* While the result is divisible by 10, and the scale > 0, divide by 10.
This operation should not lose significant digits, and gives an
opportunity to reduce the possibility of overflows in future
operations issued by the application.
*/
while (result->scale > 0) {
memcpy(quotient, running, sizeof(quotient));
remainder = VARIANT_int_divbychar(quotient, sizeof(quotient) / sizeof(DWORD), 10);
if (remainder > 0) break;
memcpy(running, quotient, sizeof(quotient));
result->scale--;
}
#endif
/* While the 256-bit result overflows, and the scale > 0, divide by 10.
This operation *will* lose significant digits of the result because
all the factors of 10 were consumed by the previous operation.
*/
while
(
result
->
scale
>
0
&&
!
VARIANT_int_iszero
(
running
+
sizeof
(
result
->
bitsnum
)
/
sizeof
(
DWORD
),
(
sizeof
(
running
)
-
sizeof
(
result
->
bitsnum
))
/
sizeof
(
DWORD
)))
{
remainder
=
VARIANT_int_divbychar
(
running
,
sizeof
(
running
)
/
sizeof
(
DWORD
),
10
);
if
(
remainder
>
0
)
WARN
(
"losing significant digits (remainder %u)...
\n
"
,
remainder
);
result
->
scale
--
;
}
/* round up the result - native oleaut32 does this */
if
(
remainder
>=
5
)
{
unsigned
int
i
;
for
(
remainder
=
1
,
i
=
0
;
i
<
sizeof
(
running
)
/
sizeof
(
DWORD
)
&&
remainder
;
i
++
)
{
ULONGLONG
digit
=
running
[
i
]
+
1
;
remainder
=
(
digit
>
0xFFFFFFFF
)
?
1
:
0
;
running
[
i
]
=
digit
&
0xFFFFFFFF
;
}
}
/* Signal overflow if scale == 0 and 256-bit result still overflows,
and copy result bits into result structure
*/
r_overflow
=
!
VARIANT_int_iszero
(
running
+
sizeof
(
result
->
bitsnum
)
/
sizeof
(
DWORD
),
(
sizeof
(
running
)
-
sizeof
(
result
->
bitsnum
))
/
sizeof
(
DWORD
));
memcpy
(
result
->
bitsnum
,
running
,
sizeof
(
result
->
bitsnum
));
}
return
r_overflow
;
}
/* cast DECIMAL into string. Any scale should be handled properly. en_US locale is
hardcoded (period for decimal separator, dash as negative sign). Returns 0 for
success, nonzero if insufficient space in output buffer.
...
...
@@ -4770,42 +4886,44 @@ HRESULT WINAPI VarDecDiv(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECI
*/
HRESULT
WINAPI
VarDecMul
(
const
DECIMAL
*
pDecLeft
,
const
DECIMAL
*
pDecRight
,
DECIMAL
*
pDecOut
)
{
/* FIXME: This only allows multiplying by a fixed integer <= 0xffffffff */
HRESULT
hRet
=
S_OK
;
VARIANT_DI
di_left
,
di_right
,
di_result
;
int
mulresult
;
if
(
!
DEC_SCALE
(
pDecLeft
)
||
!
DEC_SCALE
(
pDecRight
))
VARIANT_DIFromDec
(
pDecLeft
,
&
di_left
);
VARIANT_DIFromDec
(
pDecRight
,
&
di_right
);
mulresult
=
VARIANT_DI_mul
(
&
di_left
,
&
di_right
,
&
di_result
);
if
(
mulresult
)
{
/* At least one term is an integer */
const
DECIMAL
*
pDecInteger
=
DEC_SCALE
(
pDecLeft
)
?
pDecRight
:
pDecLeft
;
const
DECIMAL
*
pDecOperand
=
DEC_SCALE
(
pDecLeft
)
?
pDecLeft
:
pDecRight
;
HRESULT
hRet
=
S_OK
;
unsigned
int
multiplier
=
DEC_LO32
(
pDecInteger
);
ULONG
overflow
=
0
;
if
(
DEC_HI32
(
pDecInteger
)
||
DEC_MID32
(
pDecInteger
))
{
FIXME
(
"(%p,%p,%p) semi-stub!
\n
"
,
pDecLeft
,
pDecRight
,
pDecOut
);
return
DISP_E_OVERFLOW
;
}
DEC_LO32
(
pDecOut
)
=
VARIANT_Mul
(
DEC_LO32
(
pDecOperand
),
multiplier
,
&
overflow
);
DEC_MID32
(
pDecOut
)
=
VARIANT_Mul
(
DEC_MID32
(
pDecOperand
),
multiplier
,
&
overflow
);
DEC_HI32
(
pDecOut
)
=
VARIANT_Mul
(
DEC_HI32
(
pDecOperand
),
multiplier
,
&
overflow
);
if
(
overflow
)
hRet
=
DISP_E_OVERFLOW
;
else
/* multiplication actually overflowed */
hRet
=
DISP_E_OVERFLOW
;
}
else
{
if
(
di_result
.
scale
>
DEC_MAX_SCALE
)
{
BYTE
sign
=
DECIMAL_POS
;
if
(
DEC_SIGN
(
pDecLeft
)
!=
DEC_SIGN
(
pDecRight
))
sign
=
DECIMAL_NEG
;
/* pos * neg => negative */
DEC_SIGN
(
pDecOut
)
=
sign
;
DEC_SCALE
(
pDecOut
)
=
DEC_SCALE
(
pDecOperand
);
/* multiplication underflowed. In order to comply with the MSDN
specifications for DECIMAL ranges, some significant digits
must be removed
*/
WARN
(
"result scale is %u, scaling (with loss of significant digits)...
\n
"
,
di_result
.
scale
);
while
(
di_result
.
scale
>
DEC_MAX_SCALE
&&
!
VARIANT_int_iszero
(
di_result
.
bitsnum
,
sizeof
(
di_result
.
bitsnum
)
/
sizeof
(
DWORD
)))
{
VARIANT_int_divbychar
(
di_result
.
bitsnum
,
sizeof
(
di_result
.
bitsnum
)
/
sizeof
(
DWORD
),
10
);
di_result
.
scale
--
;
}
if
(
di_result
.
scale
>
DEC_MAX_SCALE
)
{
WARN
(
"result underflowed, setting to 0
\n
"
);
di_result
.
scale
=
0
;
di_result
.
sign
=
0
;
}
}
return
hRet
;
VARIANT_DecFromDI
(
&
di_result
,
pDecOut
)
;
}
FIXME
(
"(%p,%p,%p) semi-stub!
\n
"
,
pDecLeft
,
pDecRight
,
pDecOut
);
return
DISP_E_OVERFLOW
;
return
hRet
;
}
/************************************************************************
...
...
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