Is there a simple way to change a float variable that changes based on an encoder position to a fraction to the nearest 1/16”? Example: float equals 4.264. I want to display the number as 4 1/4. Because the decimal when converted to a fraction is closer to 1/4 than it is 5/16. I was hoping there was a simple solution…. Any ideas?
"to the end of the line" -you are confused with the comments.
Casting only applies to the variable immediately after it, in this case the contents of the parentheses
I am really about to show my stupidity.... Because of Order of Operations, shouldn't the 1 be added (to make it 9.448 then divided by two because it is out of the parentheses) before you divide by 2?
Can someone explain what I have been doing, because I not sure about it:
// For: https://forum.arduino.cc/t/convert-decimal-to-fraction-to-nearest-16th/1023040
//
// Convert a float number to the nearest 1/16 and display it as a fraction
//
// I put the floating point number between 0 and 5.
void setup()
{
Serial.begin(115200);
Serial.println( "Turn the knob");
}
void loop()
{
// create the input float number, between 0 and 5.
float f = (float) analogRead( A0) / 1024.0 * 5.0;
// multiply it by 16 to aim for a whole number for the 1/16 steps.
f *= 16.0;
// round it
f += 0.5;
// create the whole number
long l = (long) f;
// get the integer part of the original number
int t1 = (int) (l / 16);
Serial.print( t1);
Serial.print( " ");
// get the second part of 0...15
int t2 = (int) (l % 16);
// Solve printing it as a fraction
switch( t2)
{
case 0:
break;
case 1:
Serial.print( "1/16");
break;
case 2:
Serial.print( "1/8");
break;
case 3:
Serial.print( "3/16");
break;
case 4:
Serial.print( "1/4");
break;
case 5:
Serial.print( "5/16");
break;
case 6:
Serial.print( "3/8");
break;
case 7:
Serial.print( "7/16");
break;
case 8:
Serial.print( "1/2");
break;
case 9:
Serial.print( "9/16");
break;
case 10:
Serial.print( "5/8");
break;
case 11:
Serial.print( "11/16");
break;
case 12:
Serial.print( "3/4");
break;
case 13:
Serial.print( "13/16");
break;
case 14:
Serial.print( "7/8");
break;
case 15:
Serial.print( "15/16");
break;
}
Serial.println();
delay( 500);
}
Here we have a misunderstanding.
When I said about "...before additions" I explained why 0.268 give you 4/16 and 0.288 - 5/16
Multiplication by 32 and addition of 1 is equivalent to @Koepel multiplication by 16 and addition of 0.5. I just get doubled operands to use integers and avoid of float math.
Addition of 0.5 is frequently used way to round float before convert it to integer. Because the casting float to int just discards the fractional part, without the addition you will give 9 either from 9.2 and 9.9. But after 0.5 supplement the first give you 9.7 and converts to 9 and the second will be 10.4 and rounded to 10
What sort of encoder do you have?
Can you post link to specs/data?
Why do you need to display your values in non decimal fractions?
Surely 4.264 is closer to your measurement than converting it to an approximate?
It worries me that you are using inches, what is wrong with mm or cm?
float f;
uint8_t fraction;
void setup() {
Serial.begin(9600);
f = 0.264;
}
void loop() {
f = f +.001;
fraction = ((uint8_t)(f*32 +1))/2;
Serial.println(fraction);
Serial.println(f);
delay(1000);
}
I know that it works and gives the value that you are expecting and that is correct.
What I can't figure out is how it is taking the f value and multiplying it by 32 THEN dividing by 2 before it adds the 1 that is in the parentheses. It seems to me it should...
.264 * 32 = 8.448 THEN + 1 THEN / 2 Which gives you 4.724 which rounds to 5
It is doing this:
.264 *32 = 8.448 THEN / 2 which gives you the correct 4.224 which rounds to 4 Where does the 1 come in at?
I have added a few things to it since it closed. A lcd screen to readout the sawmill head location ia what I want to display the fraction on. I have it displaying to 3 decimal places now, but I don’t really need to be that precise. If I want to cut a 3/4 inch board it would be easier for me to see that it is on “12 - 1/2” and I need to move to “11 - 3/4” instead of 12.509 and trying to figure out where I would need to be. As for inches instead of metric. As you can see from my posts, I’m a dumb American I’m not smart enough to figure out metric!
Thanks all! I think I have a grasp on the concept. @b707, I apologize I couldn't understand why the mathematical calculation:
uint8_t fraction = ((uint8_t)(f*32 +1))/2;
did not round to the nearest whole number for example if the calculation above came up to 4.76, I expected that value to be a 5 when apparently it is not. 4.76 when stored in a uint8_t variable is a 4 not a 5..... That blew my mind.
@gfvalvo I follow your entire code fairly easily, but couldn't figure out this line:
I am still not sure how you knew to use this? Why choose 15? Because we want it broken in to 16 parts?
The number 15 is in binary 00001111 in other words it consists of 4 bits. In 4 bits you can express 16 different bit patterns which in decimal is the numbers 0 to 15, so it is splitting the number into 16 parts.
The and operation & makes sure that any number can not exceed the value of 15. Which is what you want.