1

I am trying to debug a problem unrelated to this specific code and I am looking for clues, the clue being "what value might this counter have had?" The following line of code

sprintf(strAtLeast10long, "%lld%c%.02uP", 
   input/peta, decimal, (long)((input%peta) / (peta/hundred)));

is producing "0.00P" for output.

Here is what I know about the parameters. Input is an unsigned long long with a value >= (10^12 - (10^7 / 2)). decimal = '.'

static const long long hundred =            100;
static const long long peta =  1000000000000000ULL;

Yes, I know the "%lld" would be better as "%llu" and I will fix that.

But meanwhile, I am looking for clues as to what might have been in input. The problem occurred at a customer and we do not know how to reproduce it, so adding debugging code or using a debugger is not an option.

Compiler is the IBM z/OS C++ compiler. Before you all roll your eyes and go "EBCDIC is the devil's handiwork!" it is a Posix-conformant C++ compiler and environment.

Nicole Trudeau
  • 678
  • 3
  • 8
Charles
  • 479
  • 1
  • 3
  • 13
  • Is this C code? Might be worth adding the C tag. Also specifying your compiler version and standard library might be useful. – tambre Jul 13 '17 at 17:03
  • Use `snprintf` (or perhaps `asprintf`), and test the result length. – Basile Starynkevitch Jul 13 '17 at 19:02
  • Minor: 1) `ULL` not needed in `long long peta = 1000000000000000ULL;` 2) Could use `long long peta = 1000LL * 1000 * 1000 * 1000 * 1000;` for clarity. – chux - Reinstate Monica Jul 13 '17 at 20:11
  • Wrong specifier: `"%.02u"` should be `"%.02ld"` (add `l`, `u` --> `d`.) – chux - Reinstate Monica Jul 13 '17 at 20:13
  • 1. I think any way you specify 10^15 it is lacking in clarity unfortunately. 2. My C does not require %ld or %lu, just %d or %u. It wants ll as a modifier for 64-bit values and h and hh for smaller values but l is optional with d, u or x for 32-bit values. – Charles Jul 13 '17 at 20:47
  • If `input` is an `unsigned long long` then this code causes undefined behaviour, `%lld` is only for signed long long – M.M Jul 13 '17 at 23:40

4 Answers4

1

Using all the information you provide in the most straight forward way yields the described output 0.00P for
unsigned long long input=999995000000ULL; (which I understand to be the lowest allowed value in your given scope)
and for
unsigned long long input=9999999999999ULL;, which I believe to be the highest value for the specified output.
It is reasonable to assume that any value in between also gives the same output.

You get 0.01P for unsigned long long input = 10000000000000ULL;, which is one higher.

Here is my playcode,
please check for any conflict with what you described
(I adapted the format specifier string to my compiler, gcc version 4.9.2 (tdm-1), Target: mingw32 ).

#include <stdio.h>

int main(void)
{
    char decimal='.';

    char strAtLeast10long[]="                                \0";
    static const long long hundred =            100;
    static const long long peta =  1000000000000000ULL; 

    //unsigned long long input=  9999999999999ULL;
    //unsigned long long input=   999995000000ULL;
    unsigned long long input  = 10000000000000ULL;

    sprintf(strAtLeast10long, "%I64u%c%.02luP", input/peta, decimal, (long)((input%peta) / (peta/hundred)));

    printf("%s\n", strAtLeast10long );

    return 0;
}

This answer agrees with the comment by xing, which has appeared meanwhile.

Yunnosch
  • 26,130
  • 9
  • 42
  • 54
  • Thanks. Okay, I just figured out two mistakes in my question as posted. – Charles Jul 13 '17 at 19:47
  • Thanks @xing. Okay, I just figured out two mistakes in my question as posted. I can't seem to get new lines into this comment so this is a little difficult. First, the qualification is stated incorrectly -- I counted decimals incorrectly. input is an unsigned long long with a value >= (10^15 - (10^10 / 2)). And there is one line of rounding code before the sprintf: input += peta/hundred/2; – Charles Jul 13 '17 at 19:53
  • 1
    @Charles The trouble with burying vital info in the above comment and not in the original post is that 1) folks are less likely to see it and 2) Your post is now a moving target. AFAIK, it will change again and again. Suggest a 1-time edit and append this info and append a compilable function that demos the problem. – chux - Reinstate Monica Jul 13 '17 at 20:08
  • @chux. Wish I knew how to use stackoverflow better. How do I suggest a 1-time edit? And sorry, I can't demo the problem. If I could I could easily debug it. This is unfortunately not a "what does this code do?" problem but rather "how did this code produce this output?" problem. – Charles Jul 13 '17 at 21:47
1

The first requirement for that output is:

char decimal = '.';

Then every input value in the range:

0 to (1000000000000000ULL/100 - 1)

or equivalent

0 to 10^13-1

will set the string to:

0.00P

This is because input needs to be lower than:

peta/hundred

which is 1000000000000000ULL/100

Since OP knows that input >= (10^12 - (10^7 / 2)) the final answer is:

input in the range (10^12 - (10^7 / 2)) to 10^13-1 will produce 0.00P

UPDATE

In a comment below OP changes the restriction on input so that input >= (10^15 - (10^7 / 2)) (notice 10^15 instead of 10^12 which differ from the question).

With that new restriction there are no input value that can produce the result 0.00P

In order to get the first 0 (which comes from input/peta) it is obvious that input must be less than peta.

The new requirement from OP is that input >= peta - 10000000ULL so the only interesting range is:

peta - 10000000ULL <= input <= peta - 1

All values in that range produce the result 0.99P.

Conclusion: With the given (new) restrictions there are no input value that can produce the said result

Support Ukraine
  • 42,271
  • 4
  • 38
  • 63
  • No, the code in question is only executed if input >= (10^15 - (10^10 / 2)) and (1000000000000000ULL/100) -1 fails that test. – Charles Jul 13 '17 at 21:23
  • @Charles - That is not what is written in your question! The question says: "(10^12 - (10^7 / 2))". – Support Ukraine Jul 14 '17 at 04:35
1

Sometimes one can use brute force testing.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void foo(unsigned i, unsigned long long input) {
  char decimal = '.';
  static const long long hundred = 100;
  static const long long peta = 1000000000000000ULL;
  char strAtLeast10long[10 + 100];

  // compile time warnings
  sprintf(strAtLeast10long, "%lld%c%.02uP", input / peta, decimal,
      (long) ((input % peta) / (peta / hundred)));

  if (strcmp("0.00P", strAtLeast10long) == 0) {
    printf("%u %llu %s\n", i, input, strAtLeast10long);
    fflush(stdout);
  }
}

unsigned long long rand_ull(void) {
  unsigned long long r = 0;
  for (unsigned i = 0; i < sizeof r; i++) {
    r *= 256;
    r ^= (unsigned) rand();
  }
  return r;
}

int main(void) {
  for (unsigned i = 0; i < 10000000; i++) {
    foo(i, rand_ull());
  }
  return 0;
}

Output

486814 1708844199629 0.00P
984885 8152599175962 0.00P
6266031 209118104328 0.00P
7365558 3983123923889 0.00P
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
0

I found the value in the counter in the blowup in question via an unrelated route. It is FWIW 0xFFFFFFFFFFFFFA67 or 18446744073709550183. The rounding code wraps it around to 0x0000048c27394a67 or 4999999998567 which is so small (!) it formats as 0.00P.

Sorry I didn't do a better job of describing the problem. The huge powers of 10 are a PITA to keep straight and to type correctly.

Charles
  • 479
  • 1
  • 3
  • 13
  • Not correct. input = 0xFFFFFFFFFFFFFA67 --> output: 18446.74P. The `input/peta` part can not be `0` for any input value greater than or equal to peta. – Support Ukraine Jul 14 '17 at 05:08
  • input += peta/hundred/2; per my comment above wraps it around through zero. As I said, I'm having a problem figuring out how to edit a question with appropriate clarity. – Charles Jul 14 '17 at 17:58
  • There is no `input += peta/hundred/2;` anywhere in your question. Are you a trolling? – Support Ukraine Jul 15 '17 at 07:24
  • No, I am not a trolling. My comment to the first reply said Thanks @xing. Okay, I just figured out two mistakes in my question as posted. I can't seem to get new lines into this comment so this is a little difficult. First, the qualification is stated incorrectly -- I counted decimals incorrectly. input is an unsigned long long with a value >= (10^15 - (10^10 / 2)). And there is one line of rounding code before the sprintf: input += peta/hundred/2; – Charles Jul 16 '17 at 14:24