From: SnapDive on

I have this value (it's a VarChar(36)):

9.981884727716366E-4

If I cast it as Float and then Decimal(36,24) I get

0.000998188472771640000000

Note the rounding. I don't want ...64 I want ...6366

How can I make that happen?

Thanks.


From: Eric Isaacs on
The issue is that the FLOAT (and REAL) values are just fixed
approximations of floating point/scientific notation numbers. When
you try to cast or convert a scientific notation value to fixed
number, you can lose some precision and accuracy, which is what you're
experiencing. Also, Decimal(36,24) does not seem to hold the value
anyway. Just try to assign the value to that number and you'll get an
overflow error. You need more decimal precision, from what I tested.

Here's a function you can use to convert the Scientific Notation value
directly to DECIMAL without changing any precision. I would caution
you though that your scientific notation values are probably not as
accurate as you think, since they were scientific notation values in
the beginning

GO
--/*
IF OBJECT_ID('dbo.jfn_ConvertScientificNotationToDecimal38_28', 'FN')
IS NOT NULL
DROP FUNCTION dbo.jfn_ConvertScientificNotationToDecimal38_28
--*/

IF OBJECT_ID('dbo.jfn_ConvertScientificNotationToDecimal38_28', 'FN')
IS NULL
BEGIN
EXEC ('CREATE FUNCTION
dbo.jfn_ConvertScientificNotationToDecimal38_28 () RETURNS INT AS
BEGIN RETURN 1 END')
END
GO

ALTER FUNCTION dbo.jfn_ConvertScientificNotationToDecimal38_28
(
@ScientificNotationValue VARCHAR(50)
)
RETURNS DECIMAL(38,28)
WITH SCHEMABINDING
AS --
BEGIN --Function
DECLARE @ReturnValue DECIMAL(38,28)

DECLARE @Value VARCHAR(50)
DECLARE @Exponent VARCHAR(10)
DECLARE @CharIndex INT

SET @CharIndex = CHARINDEX('E', @ScientificNotationValue)
SET @Value = SUBSTRING(@ScientificNotationValue, 0, @CharIndex)
SET @Exponent = '1' + SUBSTRING(@ScientificNotationValue,
@CharIndex, LEN(@ScientificNotationValue))

SELECT @ReturnValue = CAST(@Value AS DECIMAL(36,28)) *
CAST(CAST(@Exponent AS FLOAT) AS DECIMAL(36,28))

RETURN @ReturnValue
END --Function

-Eric Isaacs
From: Eric Isaacs on
Here's a test script for that function...

SELECT
dbo.jfn_ConvertScientificNotationToDecimal38_28('9.981884727716366E-4')
AS ReturnValue

-Eric Isaacs
From: John Bell on
On Tue, 8 Jun 2010 10:52:04 -0700 (PDT), Eric Isaacs
<eisaacs(a)gmail.com> wrote:

>The issue is that the FLOAT (and REAL) values are just fixed
>approximations of floating point/scientific notation numbers. When
>you try to cast or convert a scientific notation value to fixed
>number, you can lose some precision and accuracy, which is what you're
>experiencing. Also, Decimal(36,24) does not seem to hold the value
>anyway. Just try to assign the value to that number and you'll get an
>overflow error. You need more decimal precision, from what I tested.
>
>Here's a function you can use to convert the Scientific Notation value
>directly to DECIMAL without changing any precision. I would caution
>you though that your scientific notation values are probably not as
>accurate as you think, since they were scientific notation values in
>the beginning
>
>GO
>--/*
>IF OBJECT_ID('dbo.jfn_ConvertScientificNotationToDecimal38_28', 'FN')
>IS NOT NULL
> DROP FUNCTION dbo.jfn_ConvertScientificNotationToDecimal38_28
>--*/
>
>IF OBJECT_ID('dbo.jfn_ConvertScientificNotationToDecimal38_28', 'FN')
>IS NULL
> BEGIN
> EXEC ('CREATE FUNCTION
>dbo.jfn_ConvertScientificNotationToDecimal38_28 () RETURNS INT AS
>BEGIN RETURN 1 END')
> END
>GO
>
>ALTER FUNCTION dbo.jfn_ConvertScientificNotationToDecimal38_28
>(
> @ScientificNotationValue VARCHAR(50)
>)
>RETURNS DECIMAL(38,28)
>WITH SCHEMABINDING
>AS --
>BEGIN --Function
> DECLARE @ReturnValue DECIMAL(38,28)
>
> DECLARE @Value VARCHAR(50)
> DECLARE @Exponent VARCHAR(10)
> DECLARE @CharIndex INT
>
> SET @CharIndex = CHARINDEX('E', @ScientificNotationValue)
> SET @Value = SUBSTRING(@ScientificNotationValue, 0, @CharIndex)
> SET @Exponent = '1' + SUBSTRING(@ScientificNotationValue,
>@CharIndex, LEN(@ScientificNotationValue))
>
> SELECT @ReturnValue = CAST(@Value AS DECIMAL(36,28)) *
>CAST(CAST(@Exponent AS FLOAT) AS DECIMAL(36,28))
>
> RETURN @ReturnValue
>END --Function
>
>-Eric Isaacs

Your exponent will never require decimal (36,28) and if you make this
smaller then you won't need to change the precision. e.g.

@ReturnValue = CAST(@Value AS DECIMAL(36,24)) * CAST(CAST(@Exponent AS
FLOAT) AS DECIMAL(8,6))

John
From: Sylvain Lafontaine on
I'm working on a similar problem. It now appears to me that even if float
are stored internally with 16 digits, they are often converted to 15 digits
when printed - including when using the str() function) - or otherwise
converted to some other value such as Decimal (38,24). However, I've just
found that the convert function can print all the 16 digits when using the
style #2. With this style, a float value will always be printed on either
22 or 23 characters depending if it's positive or negative.

This means that if you have a float value, you can use something like the
following to convert it to a decimal value:

declare @n varchar(30)
set @n = '9.981884727716366E-4'

declare @f float
set @f = convert (float, @n)

declare @s as varchar(23)
set @s = convert (varchar(23), @f, 2)

declare @d decimal (36,24)

set @d = convert (decimal (36,24), left (@s, len(@s) - 5))
* convert (decimal (14,8), convert (float, '1' + right (@s, 5)))

select @d

-- If you have the possibility of having to many digits, the computation
-- won't work, for example:

set @d = convert (decimal (36,24), left (@s, len(@s) - 5))
* convert (decimal (36,24), convert (float, '1' + right (@s, 5)))

select @d

-- So you have to diminish the number of total digits in order to make it
right:

set @d = convert (decimal (36,24), left (@s, len(@s) - 5))
* convert (decimal (18,12), convert (float, '1' + right (@s, 5)))

select @d

set @d = convert (decimal (32,24), left (@s, len(@s) - 5))
* convert (decimal (28,18), convert (float, '1' + right (@s, 5)))

select @d


I don't really know what are the rules here. BTW, converting the exponent
to an integer and use it to either multiply or divide the mantissa is
probably the best way of doing while insuring of keeping the maximum number
of digit.

However, in your case, I'm not sure if you really want to convert your float
values to decimal. When using big decimals between themselves, it doesn't
take long to lose a lot of significant digits.

--
Sylvain Lafontaine, ing.
MVP - Access
Blog/web site: http://coding-paparazzi.sylvainlafontaine.com
Independent consultant and remote programming for Access and SQL-Server
(French)


"SnapDive" <SnapDive(a)community.nospam> wrote in message
news:t9ks06pmbrjkg0j5ohoog0a8c8adh349m1(a)4ax.com...
>
> I have this value (it's a VarChar(36)):
>
> 9.981884727716366E-4
>
> If I cast it as Float and then Decimal(36,24) I get
>
> 0.000998188472771640000000
>
> Note the rounding. I don't want ...64 I want ...6366
>
> How can I make that happen?
>
> Thanks.
>
>