#How to get the lenght of a number?

55 messages · Page 1 of 1 (latest)

pulsar wadiBOT
#

When your question is answered use !solved to mark the question as resolved.

Remember to ask specific questions, provide necessary details, and reduce your question to its simplest form. For tips on how to ask a good question use !howto ask.

toxic sleet
#

floor(log10(num)) + 1

past flame
#

The secret agent Programín has to send a coded message and he doesn't know how to do it. writes
a recursive module called ej3 to help you. This module must receive a number and
returns encoded, this module should not print anything on the screen. To encode the number
The procedure is as follows, the number is decomposed into figures and if the figure is a zero, it is
becomes 1, if it is a multiple of 3 its value is multiplied by 2 and in any other case it is left
how are you doing. The coded number is the result of multiplying all the figures processed as
has been indicated.
Examples:
Number: 2345789 Encoded: 241920 (obtained by 232457892)
Number: 103468 Encoded: 2304 (obtained through 1132462*8)

#

this is the actual problem

past flame
toxic sleet
#

the base-10 logarithm of a number tells you what power you need to raise 10 to to get the number. e.g. for 1000, that's 3

#

then you add 1 to that because 2.g. 256 will only give you 2.4

past flame
#

okay then why +1 ?

#

oh ok

#

but if i get 100 the log of 100 is 2

alpine umbra
#

The best (and probably) fastest way is to loop dviding the number by 10 until it reaches 0;

int numlength(long l) {
    int length = 0;
    for (; l != 0; l /= 10)
        ++length;
    return count;
}
toxic sleet
#

that's why you add 1

past flame
#

but doing 10^2 is 100 and log10(100)+1 = 3

toxic sleet
alpine umbra
#

Maybe the logorithm trick might be faster, but I have doubts about the performance of the log method

past flame
#

shit

#

you are right

toxic sleet
#

it's potentially a trickier math operation for the CPU to do

past flame
#

sooo?

toxic sleet
past flame
#

okay

alpine umbra
#

;asm -O2

#include <math.h>
int numlength(long l) {
    if (l == 0)
       return 1;
    int length = 0;
    for (; l != 0; l /= 10)
        ++length;
    return length;
}

int numlength2(long l) {
    return (int)log10(l) + 1;
}
bitter jasperBOT
#
Assembly Output
numlength:
  mov ecx, 1
  test rdi, rdi
  je .L1
  movabs rsi, 7378697629483820647
  xor ecx, ecx
.L3:
  mov rax, rdi
  add ecx, 1
  imul rsi
  mov rax, rdi
  sar rax, 63
  sar rdx, 2
  mov rdi, rdx
  sub rdi, rax
  jne .L3
.L1:
  mov eax, ecx
  ret
numlength2:
  pxor xmm0, xmm0
  sub rsp, 8
  cvtsi2sd xmm0, rdi
  call log10
  add rsp, 8
  cvttsd2si eax, xmm0
  add eax, 1
  ret

past flame
toxic sleet
#

it's the assembly that the code they posted compiles into

past flame
#

lol

alpine umbra
#

Ya just ignore it, it is just a curiosity thing on my part

#

Anyway, those are two function that can give you the length

toxic sleet
alpine umbra
#

What sizes of numbers did you test with?

#

I imagine the numbers approaching LONG_MAX, might be longer, but number closer to 0 are shorter :P

toxic sleet
#

that was 5 digit, currently rewriting to do 1, 12, 123, 1234, ... 123456789

#

this benchmark library generates some nice graphs I'm excited to see

toxic sleet
# alpine umbra I imagine the numbers approaching LONG_MAX, might be longer, but number closer t...
div/1                   time:   [1.1302 ns 1.1339 ns 1.1380 ns]
div/12                  time:   [1.6318 ns 1.6361 ns 1.6403 ns]
div/123                 time:   [2.2935 ns 2.3000 ns 2.3067 ns]
div/1234                time:   [3.1804 ns 3.1881 ns 3.1956 ns]
div/12345               time:   [4.0195 ns 4.0308 ns 4.0424 ns]
div/123456              time:   [5.1414 ns 5.1911 ns 5.2565 ns]
div/1234567             time:   [6.4852 ns 6.5035 ns 6.5222 ns]
div/123456789           time:   [8.8588 ns 8.8939 ns 8.9316 ns]

log/1                   time:   [1.5009 ns 1.5389 ns 1.5684 ns]
log/12                  time:   [1.6562 ns 1.7749 ns 1.9179 ns]
log/123                 time:   [1.5343 ns 1.5391 ns 1.5441 ns]
log/1234                time:   [1.5270 ns 1.5315 ns 1.5359 ns]
log/12345               time:   [1.5286 ns 1.5348 ns 1.5425 ns]
log/123456              time:   [1.6939 ns 1.7347 ns 1.7715 ns]
log/1234567             time:   [1.5365 ns 1.5420 ns 1.5484 ns]
log/123456789           time:   [1.5370 ns 1.5421 ns 1.5477 ns]
#

on my system at least, seems there's no reason to not use log

stray carbon
#

You might get different results if you use ffast-math

toxic sleet
#

I'm not sure about that

#

fast-math lets floating-point get a bit wonky (iirc to save time on checking edge cases), but the div method isn't using any floating points

stray carbon
#

Oh I didn't see it was integer division, sorry

toxic sleet
#

here's the actual code I benched:

fn len_div(mut l: i32) -> u32 {
    if l == 0 {
        return 1;
    }
    let mut len = 0;
    while l != 0 {
        len += 1;
        l /= 10;
    }
    len
}

fn len_log(l: i32) -> u32 {
    l.ilog10() + 1
}
stray carbon
#

It makes sense that logarithm isn't slower than repeated division, since the logarithm is probably just a taylor series under the hood

quasi granite
#

It returns the number of characters it would write if it had enough space

#

So, snprintf(NULL, 0, "%d", 37473) would return 5 for 5 digits

#

That's probably might be safer since you aren't relying on math and it's just directly telling you how many characters it's gonna write.

alpine umbra
#

Okay so my dumb ass forgot the printf's return the number of characters printed

#

I was thinking of sprintf, but thought the requirement of needing a large enough buffer was putting the cart before the horse in a sense

#

Also didn't know that it still counts beyond the n-bound

quasi granite
#

Oh it does

alpine umbra
#

TIL

quasi granite
#

This string manipulation right here is top dollar.

#

You can do everything with that. Concatenate strings, add a number to the end of a string, append a float to a string