count digit afer decimal point

Pages: 123
Thank you guys. I'm still confused about this. In my mind, multiplying a float, getting an int and then converting it into a float and then eventually there must come a value if we're dividing by 10 where the originally integer is equivalent to the float at least according to the if condition.

And I would have used a counter which I would increment for every time the value was divided by 10.

What you people seem to be saying is that they won't be equivalent.

I'll try this next week anyway after my tests. I can't use my pc to compile until then.
I'll try writing the program demonstration and posting it here by tomorrow. Thanks for baring with me guys.

I have a very strong feeling that my logic is correct.
Last edited on
In my mind, multiplying a float, getting an int and then converting it into a float and then eventually there must come a value if we're dividing by 10 where the originally integer is equivalent to the float at least according to the if condition.


The problem is that you don't know what the user originally typed in. That's the problem. If the user types in 3.1 at the keyboard, the float will be 3.099999904632568359375

If the user types in 3.10, the float stored will be 3.099999904632568359375
If the user types in 4.1597, the float stored will be 4.159699916839599609375

Do you see the problem here? If the user types in 3.10, the answer you're looking for is 310, right? You won't get that; you'll get 3099999904632568359375
I could only write this much of the script I will finish it when I come back.

But here you go guys, finally a live demonstration:
Try giving any sort of input you will observe that I was right. And I don't think we will have problem in cutting the trailing zeroes and then dividing until what we had is equivalent to the float. And if the if condition won't work then we just compare the powers of 10 to which they both are raised and then we can calculate the decimal places.

So it IS possible to calculate decimal places with math. I will finish the program when I have time.

@Deanmon your logic should be something like this.

I'll give you a cookie if you can still justify why this logic won't work. ;p

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
// Program to demonstrate that multiplication can be used 
// to find the decimal places of a floating point number

#include <iostream>
#include <cmath>

int main() {
	
	long double original_floating, temp_floating;
	int floating_int, decimal_places;
	
	while(true) {
	
		std::cout << "Enter a floating point number: ";
		std::cin >> original_floating;
	
		temp_floating = original_floating;
		
		std::cout << "\n";
		
		while (temp_floating < 10*10*10*10*10*10*10*10 /* 10^8 */) {
			temp_floating *= 10;
			std::cout << "temp_floating's value is: " << (int) temp_floating << "\n";
		}
	
		std::cout << "\nAfter while loop, temp_floating's value is: " << (int)temp_floating;
		std::cout << "\n\ntemp_floating - ceil(temp_floating) = " << (int)temp_floating - ceil(temp_floating);
		if (temp_floating - ceil(temp_floating) < 0)
			std::cout << "\ntemp_floating - ceil(temp_floating) gives -1, it still has floating point";
		else {
			std::cout << "\ntemp_floating - ceil(temp_floating) gave 0, therefore floating point eliminated";
			std::cout << "\n\t\tSo we can continue!\n";
			break;
		}
		
		std::cin.ignore();
		std::cin.get();
		system("cls");
		std::cout << "You had given a number that was no supported, try again\n\n";	   	   	   
	}

	floating_int = temp_floating;
	std::cout << "\n\n Successfully gotten integer named floating_int with value: " << floating_int;
	std::cout << "\nNow we cut off the trailing zeroes";
			
	

	std::cin.get();
	return 0;
}
Last edited on
I entered 1.1234567

The answer your code gave was 112345669, and it gives up.

You have written code that rejects any values it doesn't work on. That's hardly solving the problem, is it? You're basically accepting that there is an infinite range of numbers on which this doesn't work.

I'll give you a cookie if you can still justify why this logic won't work. ;p


Using 32 bit floats because I haven't the patience for 64 bit floats,
If the user types in 123456788, you get the 32 bit float 1.12345683574676513671875
If the user types in 123456789, you get the 32 bit float 1.12345683574676513671875

So tell me the logic you will use to know whether the answer is 123456788 or 123456789, given the 32 bit float 1.12345683574676513671875

That's your input; you receive the 32 bit float 1.12345683574676513671875 - now you tell me if I typed in 1.23456788 or 1.23456789
Last edited on
Makes sense so it would work but only up to 7 digits.

*throws cookie* But the program can calculate decimal places for up to 7 digit numbers, above which it fails, but then it's also true that all number datatypes start losing precision at one point.

But you can still use the same logic up to n number of powers of 10 if you use an arbitrary precision library for floating point. What I mean is you can keep multiplying the float by 10 without checking for whether it's more than some value but until there is no floating left which can be checked like this temp_floating - ceil(temp_floating) which returns -1 when there is floating point or you can use truncate and that will give you actual decimal part.


btw the full code since we're here anyway:

So @Deanmon you can probably follow this approach (which is lengthy) for 7 digits or wait till you learn about character strings and then you can just locate the decimal place and then subtract 1+location from the length of the string..

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
// Program to demonstrate that multiplication can be used 
// to find the decimal places of a floating point number

#include <iostream>
#include <cmath>

int main() {
	
	long double original_floating, temp_floating;
	int floating_int, decimal_places=0, temps_floating;
	
	while(true) {
	
		std::cout << "Enter a floating point number: ";
		std::cin >> original_floating;
	
		temp_floating = original_floating;
		
		std::cout << "\n";
		
		while (temp_floating < 10*10*10*10*10*10*10 /* 10^7 */) {
			temp_floating *= 10;
			std::cout << "temp_floating's value is: " << (int) temp_floating << "\n";
		}
	
		std::cout << "\nAfter while loop, temp_floating's value is: " << (int)temp_floating;
		std::cout << "\n\ntemp_floating - ceil(temp_floating) = " << (int)temp_floating - ceil(temp_floating);
		if (temp_floating - ceil(temp_floating) < 0)
			std::cout << "\ntemp_floating - ceil(temp_floating) gives -1, it still has floating point";
		else {
			std::cout << "\ntemp_floating - ceil(temp_floating) gave 0, therefore floating point eliminated";
			std::cout << "\n\t\tSo we can continue!\n";
			break;
		}
				
		std::cin.ignore();
		std::cin.get();
		system("cls");
		std::cout << "You had given a number that was no supported, try again\n\n";	   	   	   
	}

	floating_int = temp_floating;
	std::cout << "\n\n Successfully gotten integer named floating_int with value: " << floating_int;
	std::cout << "\nNow we cut off the trailing zeroes and compare the integer with the inputted number\n\n";
		
	int number = floating_int % 10;
	while(number == 0) {
		floating_int /= 10;
		number = floating_int % 10;
	}
	
	std::cout << floating_int;
	
	long double converted_float = floating_int;
	while(trunc(converted_float) != trunc(original_floating)) {
			decimal_places++;
			converted_float /= 10;
			//std::cout << converted_float;
	}
	
	std::cout << "\n\nThe number " << original_floating << " has '" << decimal_places << "' decimal places.";
		

	std::cin.get();
	return 0;
}
Last edited on
The program fails for the value 0.24.

Enter a floating point number: 0.24

temp_floating's value is: 2
temp_floating's value is: 23
temp_floating's value is: 239
temp_floating's value is: 2399
temp_floating's value is: 23999
temp_floating's value is: 239999
temp_floating's value is: 2399999
temp_floating's value is: 23999999
temp_floating's value is: 239999999

After while loop, temp_floating's value is: 239999999

temp_floating - ceil(temp_floating) = -1
temp_floating - ceil(temp_floating) gives -1, it still has floating point
Gosh darn it thanks Peter.

Here is where it gets weird.
23 is int(0.24 * 100), but if you do not typecast (0.24 * 100) to int, you get the value of 24 itself but also with no floating point.

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>

int main() {
	
	long double foo;
	
	foo = 0.24;
	std::cout<<foo*10*10; // <- comment this out
	//std::cout<<int(foo*10*10); <- try this 
	
	std::cin.get();
	return 0;
}


How does floating point decide when to round off?

Try
std::cout<<std::setprecision(4)<<foo*10*10

You will notice that there is no decimal point at all.
Now try multiplying by 10, you do not see the supposed 9999 in fact it would never show you the real value but behave like what inputted value itself while displaying and multiplying by 10 at least.

But yet when we do temp_floating - ceil(temp_floating) the compiler thinks there is a floating point.

Anybody has anything to add to above anomaly? Why isn't there a better more accurate implementation of floating point in STL?

So it's just impossible to represent 0.24 in binary?
Last edited on
So it's just impossible to represent 0.24 in binary?

It's not impossible; you can write your own floating point format that can perfectly represent the value 0.24

Why isn't there a better more accurate implementation of floating point in STL?

There will always, always be an infinite number of values that cannot be perfectly represented with a simple floating point binary representation. The onus is on YOU, the programmer, to understand the datatypes with which you are working and to use them appropriately, and if they don't do what you need then the onus is on YOU to find or write others that do.

I get that it's because of binary limitations in that 0.24 itself can't be stored because of how binary works.

But it's just weird.. you can get the actual decimal places of a small floating number relying on the compiler to round off.. but you can't get the number of decimal places itself..

Can we rely on rounding (or some kind of math) to somehow calculate the decimal places using math? That sounds impossible but there's a lot of things in this world that shouldn't exist..

So like 0.24 the constant itself is stored as 2.3999 (when the compiler interprets it) am I right?
Last edited on
When casting a floating point value to an integer the decimal part is simply lost. You can think of it as rounding towards zero. That means that if the value is only the slightest below 24 it will not get the value 24 when casted to an int.

That said, I do actually get 24 from int(0.24 * 100).

1
2
3
4
5
6
7
#include <iostream>

int main()
{
	double value = 0.24;
	std::cout << int(100 * value) << '\n';
}
24

However, if I change the type of the variable to long double I do get 23.

1
2
3
4
5
6
7
#include <iostream>

int main()
{
	long double value = 0.24;
	std::cout << int(100 * value) << '\n';
}
23

I guess this has to do with 0.24 being a double and when converting it to a long double it is not the long double value that is closest to 0.24. This problem can easily be fixed by appending an L to the end of the literal to make it a long double literal.

1
2
3
4
5
6
7
#include <iostream>

int main()
{
	long double value = 0.24L;
	std::cout << int(100 * value) << '\n';
}
24


I have to admit that I don't understand why 100 * 0.24 computes to exactly the floating point value 24 but I guess it's intentional, and probably guaranteed by the IEEE floating point standard.
I have to admit that I don't understand why 100 * 0.24 computes to exactly the floating point value 24

Via Godbolt, https://godbolt.org/z/dzOhx6 , looks like the compiler optimises the code such that 24 is used directly, so the 0.24 never exists.


It's a bit clearer to see the optimisaiton with this example: https://godbolt.org/z/IwL323

In this example, we can see that the float value is simply rounded down by the compiler: https://godbolt.org/z/z7hLn7
Last edited on
Exercise for you @Nwb. Pen and paper (possibly inaccurately) gives 0.24 in binary as (I think):
0.00111101011100001010........
  ^                  ^

with it recurring between the points indicated by a caret (^) inclusive.

Can you write a program to check that for me?
Last edited on
@Repeater but I thought optimizations like that were only possible with the "fast math" compiler option? After all, it looks like an optimization is changing the behavior of the program?
After all, it looks like an optimization is changing the behavior of the program?


Here's a page all about it, that also talks about what guarantees C++ offers; https://randomascii.wordpress.com/2013/07/16/floating-point-determinism/
@lastchance check what? Do you want me to write a program to convert decimal to binary? Is that what you mean?

I don't know how to convert fractions to binary though..

@peter then how do we get 24 instead of 23 when we work with input?

Then would the logic be accurate at least for 7 digits?
Last edited on
Repeater, thanks for the link.
Last edited on
> Then would the logic be accurate at least for 7 digits?

C++ itself makes no guarantees about the accuracy of floating point operations.
6.7.1/8 This document imposes no requirements on the accuracy of floating-point operations
http://eel.is/c++draft/basic.fundamental#8.note-1

Also see: http://eel.is/c++draft/expr.const#7.note-1

This is very interesting.

On my computer (64-bit, Debian) I still get 24 even after reading the input from the user. I tried with both GCC 4.9.2 and GCC 7.3.0 and there is no difference. I also tried it in VirtualBox (32-bit, Arch Linux) and then I get 23 with GCC 6.2.1 but 24 with Clang 3.9.1. The optimization level doesn't seem to make a difference (I didn't try -ffast-math).


@peter then how do we get 24 instead of 23 when we work with input?

You might want to use std::round in this situation.

1
2
3
4
5
6
7
8
9
#include <iostream>
#include <cmath>

int main()
{
	double value;
	std::cin >> value;
	std::cout << std::round(100 * value) << '\n';
}

Note that if you just want to print the value and don't need it as an int (like in the above example) you might want to keep it as a floating point value and rely on the output stream operator (<<) to do the rounding.
Last edited on
@Peter round works only for integers, so I am potentially losing an important decimal point if I use the function for round(). (How do I know when to round? and what if the user inputted 2.99!?)

Peter87 how is it that when you ran my program you got 23 but when you tried that bit of code you got 24?

Pages: 123