programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
• Campbell Ritchie
• Jeanne Boyarsky
• Ron McLeod
• Paul Clapham
• Liutauras Vilda
Sheriffs:
• paul wheaton
• Rob Spoor
• Devaka Cooray
Saloon Keepers:
• Stephan van Hulst
• Tim Holloway
• Carey Brown
• Frits Walraven
• Tim Moores
Bartenders:
• Mikalai Zaikin

# How to count digits after decimal point

Greenhorn
Posts: 27
1
• Number of slices to send:
Optional 'thank-you' note:
hi, it's been a long time, i'm startimg out in java again

So I have a function that accepts two double params. this function has to return boolean.
the criteria for this function to return true is
- if the two params are the same
- if the decimal place is the same up to 3 decimal places

the first "if" condition is correct already and has met the criteria right? but i'm missing the 2nd criteria.
how to compare if the decimal number of first param is equal to the 2nd param?

Saloon Keeper
Posts: 10750
86
• Number of slices to send:
Optional 'thank-you' note:
Comparing the length doesn't tell you anything. What if you have "12.3456" and "1.23456"?

You could use  indexOf() to find the period and then substring to get only the characters to the right of the period.

Marvin Domingo
Greenhorn
Posts: 27
1
• Number of slices to send:
Optional 'thank-you' note:

Carey Brown wrote:Comparing the length doesn't tell you anything. What if you have "12.3456" and "1.23456"?

You could use  indexOf() to find the period and then substring to get only the characters to the right of the period.

I tried substring

it's went wrong if the input is like (0.0, 0.0)

Carey Brown
Saloon Keeper
Posts: 10750
86
• Number of slices to send:
Optional 'thank-you' note:
As I said, your first test doesn't work.

Your second test only compares a single digit past the period.

Sheriff
Posts: 7001
6
• Number of slices to send:
Optional 'thank-you' note:
While it is certainly possible to compare two doubles by converting them to strings first, I'm not sure that this is necessarily the best way to do it.

In order to choose (and then implement) an algorithm to do this you need to know a bit more about the numbers you will be comparing. For example:
• What is the largest number you might be given. Is it large enough that the string representation of the number will be in "scientific" notation such as 1.23e108 ?
• What is the smallest number you might be given. Is it small enough that the string representation of the number will be in "scientific" notation such as 1.23e-108 ?
• What about negative numbers? Can you get these, or are all your parameters positive?
• Is zero an acceptable parameter?

• Once you are clear about the variety of parameters, you can begin to think about how to compare them.

Personally, at this point I would start writing down some "!test cases" which give the widest range of input numbers, and work out "by hand" what the result should be. Of course, most or even all of these test cases will fail, depending how much code you have written so far. Now, however your job has potentially become simpler, or at least more achievable, as it has been split into several sub-goals. If you have a good spread of test cases you can be happy that when all of them give the correct answer, you have made a working solution.

So, before we go any further, can you answer my list of questions above, and come up with some example input and results which demonstrate all the different types of numbers you may be given?

Marshal
Posts: 79273
377
• Number of slices to send:
Optional 'thank-you' note:
A double doasn't have a decimal point. All non‑integers (real numbers, etc.) have radix points, which is a decimal point in the case of a decimal number. Since doubles are demoninated in binary, their radix points are binary points, and they cannot therefore have any number of places after a decimal point. It is possible to view a double in hexadecimal, in which case you could consider it has a hexadecimal point.
Is 12.3456 or 1.23456, as somebody said earlier, supposed to be an exact value? That means, if you subtract exactly 12.3456 from it, do you get exactly 0? If so, define them as Strings, create a BigDecimal (or consider this method). BigDecimal is (sort of) represented in decimal, and has methods to give you the number of places after the decimal point.

Greenhorn
Posts: 1
• 3
• Number of slices to send:
Optional 'thank-you' note:
I'm making an assumption that this is an exercise for a beginner's coding class, so we are looking for a simple answer. There is no need to convert the numbers into strings.

I'd say your first question can be very straightforward:
if (parameter1 == parameter2)
return true;

Second question deals with numbers that differ after the third decimal place, so multiply your parameters by 1000, then cast them into integers to remove the excess decimal places.

Then compare them with the same method as the first question.

Bartender
Posts: 5466
212
• 1
• Number of slices to send:
Optional 'thank-you' note:
hi Phoebe,

welcome to the Ranch and enjoy the stay!

And a very fine first post, indeed!

Campbell Ritchie
Marshal
Posts: 79273
377
• Number of slices to send:
Optional 'thank-you' note:

Phoebe Wise wrote:I'm making an assumption that this is an exercise for a beginner's coding class, so we are looking for a simple answer. . . .

As I said earlier in this thread, there isn't a simple answer. Except for an infinitesimal proportion of doubles where the decimal value can be expressed exactly, there is no answer at all because the fraction recurs infinitely. I hope no teacher would give beginners such an impossible task. If you scroll down through this FAQ, you will find whatprints. Even thoughseems better behaved.

if (parameter1 == parameter2)
return true;

Look in the old Sun style guide (§10.5.2) and you will find you should write return (x == y); unless you also want to break out of the control structure. Remember that the imprecision inherent in floating‑point arithmetic means the == test can fail when the arithmetic should have made the two numbers equal.

. . . multiply your parameters by 1000, then cast them into integers . . .

I am afraid that may not work; if the numbers overflow such that -|x| < 0x8000_0000 (or -|x| < 0x8000_0000_0000_0000L), you will obtain ±∞ from your cast. This method and its brother) may avoid some of those problems, but will run out of range if |x| > 2⁵². Try something like this instead:-

Campbell Ritchie
Marshal
Posts: 79273
377
• Number of slices to send:
Optional 'thank-you' note:
...and welcome to the Ranch, PW (again)

Campbell Ritchie
Marshal
Posts: 79273
377
• Number of slices to send:
Optional 'thank-you' note:

A few minutes ago, I wrote:. . . will run out of range if |x| > 2⁵². . . .

I think I have got the exponent wrong and it should read

. . . will run out of range if |x| > 2⁵³. . . .

Creator of Enthuware JWS+ V6
Posts: 3411
320
• Number of slices to send:
Optional 'thank-you' note:
Congratulations Marvin Domingo,

Your question has made it to our Journal

Have a Cow!

Author
Posts: 986
3
• Number of slices to send:
Optional 'thank-you' note:
I agree that this seems like an example question that expects the answer to be simple. I also agree that it’s probably best not to convert to strings, though I think that method could work.

Someone suggested casting to int (or long) but I don’t think that’s a good idea, because it rounds the value. So (int)(x*1000) will turn 5.6789 to 5679, not 5678 [edit: no it doesn’t; see post below]. Could fix this by subtracting 0.5 or something, but that seems unnecessarily complicated.

Math.floor() is your friend.
[edit: Many edits. Replaced the original naive implementation with an ugly-ish one. Fought with the syntax highlighter.]

This does detect, to 3 places, that:
• 3.1756 is the same as 3.175
• -3.1756 is the same as -3.175
• 0.0 is not the same as Double.NaN
• 2.3e304 is not the same as 2.4e304

• Unfortunately, due to overflow it does not detect that 2.3e305 != 2.4e305. They look the same when multiplied by 1000, because 2.3e308 is out of range for a double.

Campbell Ritchie
Marshal
Posts: 79273
377
• Number of slices to send:
Optional 'thank-you' note:

Brian Cole wrote:. . . (int)(x*1000) will turn 5.6789 to 5679, not 5678. . . .

No, the cast rounds towards 0, so you get 5678.

My JShell wrote:jshell> double x =5.6789; System.out.println( (int)(x*1000) );
x ==> 5.6789
5678

Try it with −5.6789 instead.

Brian Cole
Author
Posts: 986
3
• Number of slices to send:
Optional 'thank-you' note:

Campbell Ritchie wrote:No, the cast rounds towards 0, so you get 5678.

Darn it, I’m embarrassed to have made this mistake. In my memory casting double to int truncated, but I wanted to be sure so I checked the JLS (https://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.1.3) before posting. The JLS says values are rounded but, as you say, they are “ rounding toward zero”. I misread it. That’s what I get for posting from my phone without checking.

That said, I still think Math.floor() is better than casting. Math.floor() returns a double, so we never leave the floating-point realm. It might still have overflow problems, if the exponent is within three of maximum maybe, but for example  it will handle NaNs better than casting.

I haven’t tried these dynamic Java execution thingies yet. Sounds like I should.

Campbell Ritchie
Marshal
Posts: 79273
377
• Number of slices to send:
Optional 'thank-you' note:

Last week, I wrote:. . . you will obtain ±∞ from your cast. . . .

I think I was mistaken; you would get the extreme limits of the requested integer type, which you can find in the JLS (=Java® Language Specification).

Greenhorn
Posts: 25
• Number of slices to send:
Optional 'thank-you' note:
I think Phoebe was right on target regarding the intent of the exercise (not to cover extreme conditions), and her approaches.  The test function can be simply:  For extra credit, Marvin might print some "try again" message if any parameter is too big/small.

I prefer the (int) cast over Math.floor() mentioned previously for two reasons: 1) A floating point number is stores the integer part separately from the fractional part, so the casting is a trivial operation for the JVM; and 2) any function call is going to run slower in comparison, so it's always(?) best to avoid functions/methods when you have native alternatives.  Also, the sign is preserved in the cast, so that's not a concern that needs to be tested separately.

Regarding Marvin's attempt to convert the numbers to strings, that would have worked fine (although less efficiently), but he assumed that the strings would always contain a decimal point.  He just needed to code for the possibility that indexOf(".") would find nothing, returning -1.  He may have been unaware that passing the parameter 0.0 is still just zero, so it will convert to the string "0" with no decimal point to be found.  And 1.0 is just "1", etc.

Campbell Ritchie
Marshal
Posts: 79273
377
• Number of slices to send:
Optional 'thank-you' note:

Chris Janicki wrote:I think Phoebe was right on target regarding the intent of the exercise . . .

I still think the orignal intent was at best expressed badly.

. . . 1) A floating point number is stores the integer part separately from the fractional part . . .

Please explain more. I was taught that IEE754 stores a mantissa and an exponent, and there is no such thing as an integer part and a fractional part to the IEEE754 representation of a floating‑point number.

2) any function call is going to run slower in comparison, so it's always(?) best to avoid functions/methods when you have native alternatives. . . .

Couldn't disagree more. The cast does something different from the floor() or ceil() calls, so you can't substitute one for another. Also a well‑tested method is usually better than working out your own solution with low‑level code. I don't know whether there is anything native about a cast. I would not try to code primarily for performance; that way lie errors!

Saloon Keeper
Posts: 27819
196
• Number of slices to send:
Optional 'thank-you' note:
The whole question is bogus. "double" numbers have no decimal point. They are binary, and thus what they have is a binary point. The location (scaling) of the binary point is defined by the exponent part of the double. The mantissa assumes a fixed binary point location that is scaled by the exponent. IBM used a form where it followed the first byte of the mantissa, but IIRC, it's the first bit in IEEE-java.

The difference is critical because 0.001 cannot be exactly converted to a binary floating-point any more than 1/3 can be exactly converted to a finite-decimals decimal number.

You can play games with converting the float to a string and calculating based on the string, but the string will not be converted with 100% accuracy, and as others have noted, will depend on the "human-friendly" options taken by the string formatter (this is, rounding, truncation).

Chris Janicki
Greenhorn
Posts: 25
• Number of slices to send:
Optional 'thank-you' note:
Ritchie, thanks for the critical eye!  I edited my post to remove the controversial parts.  Apparently I was wrong about the floating point representation... I had just looked it up on a generic (non-Java) site, and/or maybe I misunderstood something too.  Casting to int may still be trivial for the JVM (masking/shifting some number of bits in the mantissa?), but I don't know that yet.  And regarding the cast being "native" I should review/quote the Java Specification for clarity on that.  My thought/assumption was that cast is(?) implemented by the JVM--not hardware or the operating system--and therefore you could rely on its consistent operation to "chop off" fractional parts, like Math.floor().

I still prefer to avoid functions calls whenever possible.  My "mission-critical" (24x7x365) commercial app runs sometimes 10x faster than competitors that dive deep into frameworks and functions, and I don't think I've ever had a "gotcha" bug due to using low(er)-level code.  And even it there was an occasional bug to squash, it would be worth it, to me.  But that doesn't pertain to the original question, so I removed that part too, and we can quietly disagree on the pros/cons.  ;-)

Greenhorn
Posts: 4
• Number of slices to send:
Optional 'thank-you' note:
Methinks the string approach is simpler.

Mind you, you still have that age old problem with math operations which amplify the storage precision,
e.g isEqual ( (2.3 / 10.0) , 0.23) will not be equal.

Tim Holloway
Saloon Keeper
Posts: 27819
196
• Number of slices to send:
Optional 'thank-you' note:

Chris Janicki wrote:Ritchie, thanks for the critical eye!  I edited my post to remove the controversial parts.  Apparently I was wrong about the floating point representation... I had just looked it up on a generic (non-Java) site, and/or maybe I misunderstood something too.  Casting to int may still be trivial for the JVM (masking/shifting some number of bits in the mantissa?), but I don't know that yet.  And regarding the cast being "native" I should review/quote the Java Specification for clarity on that.  My thought/assumption was that cast is(?) implemented by the JVM--not hardware or the operating system--and therefore you could rely on its consistent operation to "chop off" fractional parts, like Math.floor().

I still prefer to avoid functions calls whenever possible.  My "mission-critical" (24x7x365) commercial app runs sometimes 10x faster than competitors that dive deep into frameworks and functions, and I don't think I've ever had a "gotcha" bug due to using low(er)-level code.  And even it there was an occasional bug to squash, it would be worth it, to me.  But that doesn't pertain to the original question, so I removed that part too, and we can quietly disagree on the pros/cons.  ;-)

Depending on the hardware, casting a float/double/long double to an integer type may be a single machine-language instruction. That's the JVM's problem, but a cast is a truncating operation, not a rounding operation and can potentially fail because 10E243 can't possibly fit in a 64-bit integer.

Don't be too quick to make monster modules because you're afraid of method call overhead. Modern compilers will often inline code when it's deemed efficient to do so and you're optimizing for time, not memory). Inlining probably first appeared as an explicit request in early C++, but these days is often automatic.

Even when an explicit call is generated in bytecode, that's not the end of it, since the JIT compiler might have its own ideas.

When you're talking whole libraries, it can be different, since libraries are typically tuned to a general audience, though there you're trading YOUR time for the machine's and in today's "git 'er Dun!" world, that's often frowned on by management (hardware is cheaper than you are). But optimization on low-level calls to simple methods is akin to coding everything in assembly. The saving are not only mostly lost as the system gets more complex, but also the maintenance costs go up.

Campbell Ritchie
Marshal
Posts: 79273
377
• Number of slices to send:
Optional 'thank-you' note:

Chris Janicki wrote:Ritchie, thanks for the critical eye!

Sorry for being critical, but thank you for taking it well.

I edited my post to remove the controversial parts. . . .

Plkease don't edit posts that have been replied to; it makes the reply very confusing. I have pulled rank, and reverted thed edit.

It makes for more interesting and informative discussions when people disagree with each other.

Brian Cole
Author
Posts: 986
3
• Number of slices to send:
Optional 'thank-you' note:

Harold Tee wrote:Methinks the string approach is simpler.

Mind you, you still have that age old problem with math operations which amplify the storage precision,
e.g isEqual ( (2.3 / 10.0) , 0.23) will not be equal.

This code is sort of doing it twice. Once you've assigned truncated values to a and b, you could simply compare them and be done with it. Or, if you're going to do the String.format("%.3f", a) conversion to String anyway, you needn't have truncated them to three digits first. Or am I missing something?

Campbell Ritchie
Marshal
Posts: 79273
377
• Number of slices to send:
Optional 'thank-you' note:

Tim Holloway wrote:. . . Depending on the hardware, casting a float/double/long double to an integer type may be a single machine-language instruction. That's the JVM's problem . . .

Agree; it occurs pretty quickly and whether it is done by the JVM o rnatively is something we can ignore.

can potentially fail because 10E243 can't possibly fit in a 64-bit integer.

I know you think I read the JLS as bedtime reading, but I don't. i can however remember that such large numbers are rounded to the largest (or most negative) values for the integer type. JLS link. I also got that bit wrong somewhere this week

Campbell Ritchie
Marshal
Posts: 79273
377
• Number of slices to send:
Optional 'thank-you' note:

Tim Holloway wrote:The whole question is bogus. . . . .

Agree. I hope there isn't some lecturer giving their students that sort of question.

Brian Cole
Author
Posts: 986
3
• Number of slices to send:
Optional 'thank-you' note:

Brian Cole wrote:Math.floor() is your friend.
[edit: Many edits. Replaced the original naive implementation with an ugly-ish one. Fought with the syntax highlighter.]

This does detect, to 3 places, that:

• 3.1756 is the same as 3.175
• -3.1756 is the same as -3.175
• 0.0 is not the same as Double.NaN
• 2.3e304 is not the same as 2.4e304

• I guess this refactoring does the same thing more efficiently:

Campbell Ritchie wrote:

Tim Holloway wrote:The whole question is bogus. . . . .

Agree. I hope there isn't some lecturer giving their students that sort of question.

Not sure I completely agree, but the question should have been phrased with care.

Campbell Ritchie
Marshal
Posts: 79273
377
• Number of slices to send:
Optional 'thank-you' note:

Brian Cole wrote:. . .

Campbell Ritchie wrote:. . . I hope there isn't some lecturer giving their students that sort of question.

Not sure I completely agree, but the question should have been phrased with care.

If your solution is correct, and i had a rather similar solution myself, then the question is valid but badly phrased. If somebody is really trying to extract places after the decimal point from a recurring number, then it is still a bogus question.
I think it is more likely that this is a problem about not “phrased with care”. Maybe the original was expressed more elarly and there have been errors in transmission.

Tim Holloway
Saloon Keeper
Posts: 27819
196
• Number of slices to send:
Optional 'thank-you' note:

Campbell Ritchie wrote:

Tim Holloway wrote:. . . Depending on the hardware, casting a float/double/long double to an integer type may be a single machine-language instruction. That's the JVM's problem . . .

Agree; it occurs pretty quickly and whether it is done by the JVM o rnatively is something we can ignore.

can potentially fail because 10E243 can't possibly fit in a 64-bit integer.

I know you think I read the JLS as bedtime reading, but I don't. i can however remember that such large numbers are rounded to the largest (or most negative) values for the integer type. JLS link. I also got that bit wrong somewhere this week

Yeeks!

jls wrote:
Despite the fact that overflow, underflow, or other loss of information may occur, a narrowing primitive conversion never results in a run-time exception (§11.1.1).

I'm not even sure that the C programming language is that casual. I'm having second thoughts about using Java to launch my next space probe.

Harold Tee
Greenhorn
Posts: 4
• Number of slices to send:
Optional 'thank-you' note:

Brian Cole wrote:
This code is sort of doing it twice. Once you've assigned truncated values to a and b, you could simply compare them and be done with it. Or, if you're going to do the String.format("%.3f", a) conversion to String anyway, you needn't have truncated them to three digits first. Or am I missing something?

Yes, you are right. I thought I could circumvent the rounding of String.format with
truncation, but of course, number truncation presents it's own problems (overflow).

Here is another attempt using full precision and string truncation;

Campbell Ritchie
Marshal
Posts: 79273
377
• 1
• Number of slices to send:
Optional 'thank-you' note:

Harold Tee wrote:. . .

Really? You don't use compareTo() to test whether two Strings have the same content; you use equals().
Don't write if (something) return true; return false;.
Write return something;. See the old Sun style guide.

Master Rancher
Posts: 4851
74
• 2
• Number of slices to send:
Optional 'thank-you' note:
Maybe this is a little late, but...

It occurs to me that there's some ambiguity in the original problem statement - depending on how we interpret "if the decimal place is the same up to 3 decimal places".

Consider:

isEqual(0.123, 0.1229999999)

Should these be considered equal?  The way I was raised, if you round both of those to 3 decimal places, you get 0.123 for both.  So they're equal.  But if you truncate both to 3 digits, you get 0.122 and 0.123, which are not equal.

Either of these answers seems defensible to me, but if you ask the person who gave you the problem, they may expect that one answer is "correct", while the other is not.  It might be a good idea to ask which one they mean.

Note that while I personally think we should obviously use rounding rather than truncation, and it seems very justifiable in my example... there are other examples where the "obvious" answer is perhaps less obvious:

isEqual(0.123499999, 0.1235000001)

Here with rounding we get 0.123 and 0.124 - not equal.  But with truncation we get 0.123 for both - equal.

The point is, there are always going to be values where a very tiny difference will make the difference between equal and not equal. And it's worthwhile to think about those borderline cases, and find out what the requirements are in such cases.

Campbell Ritchie
Marshal
Posts: 79273
377
• Number of slices to send:
Optional 'thank-you' note:
That is what Brian Cole meant by, “phrased with care.” Since OP hasn't come back, maybe that is something we shall never know. Maybe the students were given freedom about how they interpret the question.

Piet Souris
Bartender
Posts: 5466
212
• Number of slices to send:
Optional 'thank-you' note:
I am convinced that the man who gave this exercise to the students did not want to see a simple piece of code like the code in OP's opening post, but a complete essay where all the points of the posts above are being discussed.

Greenhorn
Posts: 2
• Number of slices to send:
Optional 'thank-you' note:

Phoebe Wise wrote:I'm making an assumption that this is an exercise for a beginner's coding class, so we are looking for a simple answer. There is no need to convert the numbers into strings.

I'd say your first question can be very straightforward:
if (parameter1 == parameter2)
return true;

Second question deals with numbers that differ after the third decimal place, so multiply your parameters by 1000, then cast them into integers to remove the excess decimal places.

Then compare them with the same method as the first question.

Certainly! Assuming you are working with a programming language like Python, here is a simple representation:

This Python code defines two functions. The first function (are_parameters_equal) compares two parameters directly, and the second function (are_numbers_equal_up_to_three_decimals) scales the numbers by 1000 to effectively compare them up to three decimal places.

Campbell Ritchie
Marshal
Posts: 79273
377
• Number of slices to send:
Optional 'thank-you' note:
Welcome to the Ranch

I am afraid that a simple (int) cast can introduce errors into your equality test. I shall leave it as an exercise for the reader to find an example of such an error.

Rancher
Posts: 1093
29
• 1
• Number of slices to send:
Optional 'thank-you' note:
Marvin,

if this is a exercise for a beginning coding class, then look back on the instruction leading up to the assignment: if it is anything like any of the classes i took, then the instructor basically told you what he or she wanted you to do for the solution.  assignments are usually done to check to see if you understand the material that has been covered leading up to the assignment.  if you do not do that, then the instructor does not get the feedback he or she is looking for.

if you are working with string manipulation, then by all means, use the sting manipulation functions and check, it not then a simple multiply both by 10000 and check the integer values, but are very simple algorithms.  choose the one your instructor in expecting and ask for help, if you don't understand, on that solution.

Les

 Story like this gets better after being told a few times. Or maybe it's just a tiny ad: a bit of art, as a gift, the permaculture playing cards https://gardener-gift.com