Count number of digits after `.` in floating point numbers?
The problem isn't really solvable as stated, since floating-point is typically represented in binary, not in decimal. As you say, many (in fact most) decimal numbers are not exactly representable in floating-point.
On the other hand, all numbers that are exactly representable in binary floating-point are decimals with a finite number of digits -- but that's not particularly useful if you want a result of 2 for 3.44
.
When I run your code snippet, it says that 3.44
has 2 digits after the decimal point -- because 3.44 * 10.0 * 10.0
just happens to yield exactly 344.0
. That might not happen for another number like, say, 3.43
(I haven't tried it).
When I try it with 1.0/3.0
, it goes into an infinite loop. Adding some printf
s shows that no
becomes exactly 33333333333333324.0
after 17 iterations -- but that number is too big to be represented as an int
(at least on my system), and converting it to int
has undefined behavior.
And for large numbers, repeatedly multiplying by 10 will inevitably give you a floating-point overflow. There are ways to avoid that, but they don't solve the other problems.
If you store the value 3.44
in a double
object, the actual value stored (at least on my system) is exactly 3.439999999999999946709294817992486059665679931640625
, which has 51 decimal digits in its fractional part. Suppose you really want to compute the number of decimal digits after the point in 3.439999999999999946709294817992486059665679931640625
. Since 3.44
and 3.439999999999999946709294817992486059665679931640625
are effectively the same number, there's no way for any C function to distinguish between them and know whether it should return 2 or 51 (or 50 if you meant 3.43999999999999994670929481799248605966567993164062
, or ...).
You could probably detect that the stored value is "close enough" to 3.44
, but that makes it a much more complex problem -- and it loses the ability to determine the number of decimal digits in the fractional part of 3.439999999999999946709294817992486059665679931640625
.
The question is meaningful only if the number you're given is stored in some format that can actually represent decimal fractions (such as a string), or if you add some complex requirement for determining which decimal fraction a given binary approximation is meant to represent.
There's probably a reasonable way to do the latter by looking for the unique decimal fraction whose nearest approximation in the given floating-point type is the given binary floating-point number.
Find the number of digits after the decimal point
Here's a shortcut that you might like:
def num_after_point(x):
s = str(x)
if not '.' in s:
return 0
return len(s) - s.index('.') - 1
Count number of decimal places in a Float (or Decimal) in Swift
Doing this with Decimal is fairly straightforward, provided you correctly create your Decimal. Decimals are stored as significand * 10^exponent
. significand
is normalized to the smallest integer possible. So for 1230, the significand is 123 and the exponent is 1. For 1.23 the significand is also 123 and the exponent is -2. That leads us to:
extension Decimal {
var significantFractionalDecimalDigits: Int {
return max(-exponent, 0)
}
}
However, you must be very careful constructing your Decimal. If you construct it from a Double, you will already have applied binary rounding errors. So for example:
let n = Decimal(0.111) // 0.11100000000000002048 because you passed a Double
n.significantFractionalDecimalDigits // 20
vs.
let n = Decimal(string: "0.111")!
n.significantFractionalDecimalDigits // 3 what you meant
Keep in mind of course that Decimal has a maximum number of significant digits, so it may still apply rounding.
let n = Decimal(string: "12345678901235678901234567890.1234567890123456789")!
n.significantFractionalDecimalDigits // 9 ("should" be 19)
And if you're walking down this road at all, you really must read the Floating Point Guide and the canonical StackOverflow question: Is floating point math broken?
How to get the count of digits after the decimal point in a float column in ms sql?
I have received from my friend a very simple solution which is just great. So I will post the workaround in order to help others in the same position as me.
First, make function:
create FUNCTION dbo.countDigits(@A float) RETURNS tinyint AS
BEGIN
declare @R tinyint
IF @A IS NULL
RETURN NULL
set @R = 0
while @A - str(@A, 18 + @R, @r) <> 0
begin
SET @R = @R + 1
end
RETURN @R
END
GO
Second:
select MY_FIELD,
dbo.countDigits(MY_FIELD)
from MY_TABLE
Using the function will get you the exact number of digits after the decimal point.
Related Topics
Mysql Split Comma Separated String into Temp Table
Detect If Value Is Number in MySQL
How to Select Rows With No Matching Entry in Another Table
Mysql - Get All Records That Have More Than 1 Record for the Same Id
H2 Database. How to Convert Date to Seconds in SQL
Remove Multiple Keys from Jsonb Column in One Statement
Replace Default Null Values Returned from Left Outer Join
Loop Through Table Rows and Call Stored Procedure on Every Row
How to Tell If a Value Is Not Numeric in Oracle
How to Resolve MySQL Error Code: 1292. Truncated Incorrect Double Value
Sql Select Count for Multiple Columns in a Single Query
Select Only Rows That Contain Only Alphanumeric Characters in MySQL
Deleting a Specific Character in a String from a Pattern
How to Combine First Name, Middle Name and Last Name in SQL Server
Sql - Sum of Positive and Negative Numbers Using Subquery
Mysql - Move Rows from One Table to Another