Arduino, how to grab the first 3 MSDs of an unsigned long integer

Thread Starter

joblake326

Joined Jan 9, 2022
21
Sounds simple but I can't find anything that addresses what I'm trying to do...or at least anything I can understand : (
It seems simple enough, I think.
I have an unsigned long variable with an incrementing big number in it but I only care about the first 3 or 4 digits:
65535
I want
655

There's a bunch of stuff that does it but it's all for strings.
A little help please?
 

BobTPH

Joined Jun 5, 2013
8,813
That works for 5 digit numbers, but I think he wants the 3 most significant digits for any number.

If the number is 123456, yould need to divide by 1000.

You need to keep dividing by 10 until you get a zero, the pick a divisor based on how many iterations that takes.

Bob
 

Thread Starter

joblake326

Joined Jan 9, 2022
21
yeah. Division makes sense. I keep thinking of it as a string where you can trim it. But it's just a number. So division is better than converting to a string and trimming it?
 

Thread Starter

joblake326

Joined Jan 9, 2022
21
I have three timers. 0 - 999 seconds each. I want to display each of them (on a TFT LCD) counting down from whatever the user sets them to. They're driven by millis() so I've got 1000 counts for each second. So I guess dividing by 1000 is the way to go?
 

djsfantasi

Joined Apr 11, 2010
9,156
If you have a log function, take the log of the number (if all you have is the natural log, divide that result by ln(10)). Add 1 to the integer part. That’s the number of digits. If the result is 3 or less, the number IS the first 3 digits (or less if the original number is 99 or less). Otherwise, subtract 3 and raise 10 to the result. Divide the original number by that result and take the integer part. That’s the first 3 digits.

Or convert to a string, take the first 3 characters and convert to an integer.
 

Thread Starter

joblake326

Joined Jan 9, 2022
21
If you have a log function, take the log...Otherwise, subtract 3 and raise 10....Divide....by that ... integer part...That’s the first 3 digits....Or convert to a string...take the first 3 character....convert to an integer.
Me thinks this is getting more involved than I need (or want) it to. In other words, my head is going to explode.

Simply put, all I need to do is to take the output of my (decrementing) counter unsignedLong and deliver it to the LCD screen.
That's it.

This is how my journey into the abyss started:

mylcd.Print_String(unsignedLong, column, row);

Problem with that is when unsignedLong goes from 1000 to 999, it leaves the LSD 0 on the screen; i.e. 9990.

A common solution is to clear the screen for every write. To me, that seemed like a brute force approach.
I was looking for something a bit more eloquent.

So I stumbled across this little diddy and it works because it's always writing the same number of characters to the screen.
Can't say that I fully understand what's going on under the hood but at least there's no more LSD 0 getting stuck on the screen -- because it is replaced with a blank/space/null---whatever nothing is called in this context.

char display_buffer[4];
sprintf(display_buffer, "%u ", unsignedLong);
mylcd.Print_String(display_buffer, column, row);


But I only want the first 3 MSDs to go to the screen.
I've tried all kinds of approaches and they've all failed for one reason or another.
I'm VERY green at this C++ stuff---even though I'm very gray---circa 1956. Yikes.
I find all this business with strings and chars to be complete jibber jabber.

So I'm going to open up the floor to your suggestions.
Extra points go to the simplest solution : )


Thanks!
-Grampa John
 
Last edited:

ApacheKid

Joined Jan 12, 2015
1,533
Sounds simple but I can't find anything that addresses what I'm trying to do...or at least anything I can understand : (
It seems simple enough, I think.
I have an unsigned long variable with an incrementing big number in it but I only care about the first 3 or 4 digits:
65535
I want
655

There's a bunch of stuff that does it but it's all for strings.
A little help please?
I'd suggest a conversion here, convert the binary to BCD, then you have a set of distinct decimal digits and can do what you want with them.
 

ApacheKid

Joined Jan 12, 2015
1,533
OK here's something drummed up in C# (which is just easier at this moment)

1641999559445.png

You can see you get an array of bytes each byte is 1 decimal digit (this is technically called "unpacked BCD).

The least significant decimal digit is the lowest array element.

Now you just need to manipulate that array to strip off what you don't want and so on, if you want the first three most significant decimal digits its easy, iterate backwards and return the first three bytes starting at the first non-zero byte, in this case you get 461.

This kind of conversion incidentally is one of the several steps in converting an int to a string but relying on string conversions can incur serious costs sometimes so I avoid it where possible.
 
Last edited:

ApacheKid

Joined Jan 12, 2015
1,533
adding a check and a break here also speeds up the code:

1642000264596.png

The C# language supports a native decimal type so doing what you are trying to do, is a bit simpler in reality in C#.
 

panic mode

Joined Oct 10, 2011
2,715
yes but Arduino is not powerful, resources are limited.
casting 16bit number (a 2 byte value) into a 20-byte array as a first step is a lot of unnecessary operations.
 

Thread Starter

joblake326

Joined Jan 9, 2022
21
I think everyone is still responding to my earlier posts. Read my last LENGTHY post.
Hopefully it will clarify what I really need.
I'm looking for simple here....
 

ApacheKid

Joined Jan 12, 2015
1,533
yes but Arduino is not powerful, resources are limited.
casting 16bit number (a 2 byte value) into a 20-byte array as a first step is a lot of unnecessary operations.
Yes, I cannot comment on that, I have no idea what the true performance of that code will be nor of the constraints that are in place.
 

KeithWalker

Joined Jul 10, 2017
3,063
Manipulating strings of numbers in the Arduino ide is possible but very awkward.
The simplest way get the first three digits would be to make a loop that divides the integer by ten and test for <1,000.
This could take a number if iterations because a long unsigned integer can contain up to ten digits.
 
Last edited:

ApacheKid

Joined Jan 12, 2015
1,533
Me thinks this is getting more involved than I need (or want) it to. In other words, my head is going to explode.

Simply put, all I need to do is to take the output of my (decrementing) counter unsignedLong and deliver it to the LCD screen.
That's it.

This is how my journey into the abyss started:

mylcd.Print_String(unsignedLong, column, row);

Problem with that is when unsignedLong goes from 1000 to 999, it leaves the LSD 0 on the screen; i.e. 9990.

A common solution is to clear the screen for every write. To me, that seemed like a brute force approach.
I was looking for something a bit more eloquent.

So I stumbled across this little diddy and it works because it's always writing the same number of characters to the screen.
Can't say that I fully understand what's going on under the hood but at least there's no more LSD 0 getting stuck on the screen -- because it is replaced with a blank/space/null---whatever nothing is called in this context.

char display_buffer[4];
sprintf(display_buffer, "%u ", unsignedLong);
mylcd.Print_String(display_buffer, column, row);


But I only want the first 3 MSDs to go to the screen.
I've tried all kinds of approaches and they've all failed for one reason or another.
I'm VERY green at this C++ stuff---even though I'm very gray---circa 1956. Yikes.
I find all this business with strings and chars to be complete jibber jabber.

So I'm going to open up the floor to your suggestions.
Extra points go to the simplest solution : )


Thanks!
-Grampa John
Well if performance is tight then avoid string conversions and sprintf, as soon as you bring these in things get very unpredictable, many string functions rely on heap allocations too which can impact memory use etc.
 

Thread Starter

joblake326

Joined Jan 9, 2022
21
Well if performance is tight then avoid string conversions and sprintf, as soon as you bring these in things get very unpredictable, many string functions rely on heap allocations too which can impact memory use etc.
I wouldn't say performance is tight. I just want a solution that gives me the end result that I'm looking for. No more, no less.
Doesn't seem like this should be a big deal.
So if you recommend avoiding string conversions and sprintf, then how would you do it?
 
Top