help needed to speed up function

i have a long value of time as HHMMSSMsMsms
and i neeed to get the HH, MM and SS from it many times

uint32_t x = HHMMSSMsMsms;
uint8_t HH = 0;
uint8_t MM = 0; 
uint8_t SS = 0;

void SplitTime(uint_32 GPS_Time)
{
	HH = GPS_Time \ 10000000L;
	MM = ((GPS_Time \ 100000L) % 100);
	SS = ((GPS_Time \ 1000L) % 100);
}

is there a way to improve the speed of the function?

is there a way to improve the speed of the function?

The modulo function is not the fastest function. Avoid it, if you can. Once you've determined the hours value, subtract that value (times the appropriate factor) from the initial value. What is left is the time in minutes and seconds.

Determine minutes, subtract that value (times the appropriate factor) from the initial value. What is left is the time in seconds.

No modulo operations needed.

HH = GPS_Time \ 10000000L;

This isn't doing a division, you know.

unsigned long GPS_Time = 235959999;
char HH = 0;
char MM = 0; 
char SS = 0;
unsigned long t = 0;
void setup()
{
  Serial.begin(9600);
  t = micros();
  for(int i=0; i<1000; i++)
    SplitTime();
  Serial.print("Time:");Serial.print((micros() - t)/1000);Serial.println("us");
  Serial.print("HH:");Serial.println(HH, DEC);
  Serial.print("MM:");Serial.println(MM, DEC);
  Serial.print("SS:");Serial.println(SS, DEC);
  t = micros();
  for(int i=0; i<1000; i++)
    SplitTime1();
  Serial.print("Time:");Serial.print((micros() - t)/1000);Serial.println("us");
  Serial.print("HH:");Serial.println(HH, DEC);
  Serial.print("MM:");Serial.println(MM, DEC);
  Serial.print("SS:");Serial.println(SS, DEC);
  t = micros(); 
  for(int i=0; i<1000; i++)
    SplitTime2();
  Serial.print("Time:");Serial.print((micros() - t)/1000);Serial.println("us");
  Serial.print("HH:");Serial.println(HH, DEC);
  Serial.print("MM:");Serial.println(MM, DEC);
  Serial.print("SS:");Serial.println(SS, DEC);  
}
void loop()
{
}

void SplitTime()
{
  	HH = GPS_Time / 10000000L;
	MM = ((GPS_Time / 100000L) % 100);
	SS = ((GPS_Time / 1000L) % 100);
}

void SplitTime1()
{
	HH = GPS_Time / 10000000L;
	MM = (GPS_Time - HH * 10000000L)/100000L; ; 
	SS = (GPS_Time - HH * 10000000L - MM * 100000L)/1000;
}

void SplitTime2()
{
	HH = GPS_Time / 10000000L;
        unsigned long H = HH * 10000000L;
	MM = (GPS_Time - H)/100000L;
        unsigned long M = MM * 100000L;
	SS = (GPS_Time - H - M)/1000;
}

Time:194us @2396 kb
HH:23
MM:59
SS:59
Time:126us @ 2514 kb
HH:23
MM:59
SS:59
Time:125us @ 2494 kb
HH:23
MM:59
SS:59

Can it be done faster and with smaller memory foot print?

The trick to this is to try to use the minimum number of long divisions (and note that % remainder is a division).
My attempt shaved off a microsecond on my Duemilanove.

void SplitTime3()
{
  int hm = GPS_Time/100000L;
  unsigned int rem = GPS_Time%100000L;
  
  HH = hm/100;
  MM = hm%100;
  SS = rem/1000;
}

Time:191us
HH:23
MM:59
SS:59
Time:124us
HH:23
MM:59
SS:59
Time:123us
HH:23
MM:59
SS:59
Time:122us
HH:23
MM:59
SS:59

You will probably find that you can have fast or small code, but not both.

But why do you need to do this so fast anyway?

Pete

void SplitTime4()
{
        unsigned long S = GPS_Time / 1000;
        HH = S/10000; // 23
        unsigned int T = S-HH*10000; //5959
        // MM = (T *5243L >> 19);    // 95us but unclear
        MM = T/100;   // 96us
        SS = T - MM*100;
}

Time:96us
HH:23
MM:59
SS:59

variation on 3 with a bit of 4

void SplitTime5()
{
  int hm = GPS_Time/100000L;
  unsigned int rem = GPS_Time - hm*100000L;
  
  HH = hm/100;
  MM = hm - HH*100;
  SS = rem/1000;
}

Time:76us
HH:23
MM:59
SS:59

  • update -
void SplitTime6()
{
  unsigned int hm = GPS_Time/100000UL;
  unsigned int rem = GPS_Time - hm*100000UL;
  
  HH = hm/100;
  MM = hm - HH*100;
  SS = rem/1000;
}

Time:74us
HH:23
MM:59
SS:59

Nice :slight_smile:

Pete

This probably isn't going to make a lot of sense all by itself Nick. Why not occasionally add something constructive instead of just trashing everybody's typo mistakes.

I disagree.
Nick is an experienced member here, and if he says there's something wrong with your code, you'd better go and find out what it is.
And if you do expend the effort, you can be assured that the answer will stick with you much better than if you'd been given the answer.

Delta_G:
This probably isn't going to make a lot of sense all by itself Nick. Why not occasionally add something constructive instead of just trashing everybody's typo mistakes.

I'm not trashing it. It may have slipped by - that is, it didn't occur to him/her to closely look at that line. Some early responses didn't pick it up.

I'm trying to encourage people to think for themselves rather than server up pre-canned answers.

Why not occasionally add something constructive ...

I believe I often add constructive things. Ask other people here.

Sometimes I get the impression though that some posters bang some code on the site here, say "it doesn't work" and sit back waiting for the fixed code to be posted for them. Hinting at problem areas is supposed to get the old gray matter working, so that next time, they can solve it for themselves.

The data format is not entirely clear to me, but,

you obviously don't need to compute the minutes and hours again and again if the seconds yet did not change.

typo yes but it's trivial + won't compile anyway. Sometimes people see it and correct it quickly.

Trivial this time, yes, but we've had hard to spot errors caused by misplaced line continuations like this one.

AWOL:
Trivial this time, yes, but we've had hard to spot errors caused by misplaced line continuations like this one.

Well I'd say he just pointed at it using a single line. It is common experience indeed to see some "trashing" become added to posts, even if the participants really give a good contribution.

If the people doing it are professional and also contribute innovation, ideas, not just criticism, I don't mind it.

Often I'd read a post again for lexical typo's and correct them.

There is a bug in the time measurement

  t = micros();
  for(int i=0; i<1000; i++)
    SplitTime();
  Serial.print("Time:");Serial.print((micros() - t)/1000);Serial.println("us");

should be

  t = micros();
  for(int i=0; i<1000; i++)
    SplitTime();
  t = micros() - t;  // <<<<<<<<<<<<<<<<<<
  Serial.print("Time:");Serial.print(float(t)/1000);Serial.println("us");

As you do not want to take the printing of "Time: " in the measurement

The fastest version sofar goes from 74 us to

Time:70.93us
HH:23
MM:59
SS:59

The "" was not a mistake
in other programming language "" returns the integer part of a division
bad habits die hard

Interesting. So it wasn't a typo, as others have suggested. And I wasn't nitpicking. Glad that is cleared up.