示例#1
0
static int check_storage_number_exists() {
    uint32_t flags = SN_EXISTS;


    for(flags = 0; flags < 7 ; flags++) {
        if(get_storage_number_flags(flags << 24) != flags << 24) {
            fprintf(stderr, "Flag 0x%08x is not checked correctly. It became 0x%08x\n", flags << 24, get_storage_number_flags(flags << 24));
            return 1;
        }
    }

    flags = SN_EXISTS;
    calculated_number n = 0.0;

    storage_number s = pack_storage_number(n, flags);
    calculated_number d = unpack_storage_number(s);
    if(get_storage_number_flags(s) != flags) {
        fprintf(stderr, "Wrong flags. Given %08x, Got %08x!\n", flags, get_storage_number_flags(s));
        return 1;
    }
    if(n != d) {
        fprintf(stderr, "Wrong number returned. Expected " CALCULATED_NUMBER_FORMAT ", returned " CALCULATED_NUMBER_FORMAT "!\n", n, d);
        return 1;
    }

    return 0;
}
示例#2
0
calculated_number unpack_storage_number(storage_number value)
{
	if(!value) return 0;

	int sign = 0, exp = 0;

	value ^= get_storage_number_flags(value);

	if(value & (1 << 31)) {
		sign = 1;
		value ^= 1 << 31;
	}

	if(value & (1 << 30)) {
		exp = 1;
		value ^= 1 << 30;
	}

	int mul = value >> 27;
	value ^= mul << 27;

	calculated_number n = value;

	// fprintf(stderr, "UNPACK: %08X, sign = %d, exp = %d, mul = %d, n = " CALCULATED_NUMBER_FORMAT "\n", value, sign, exp, mul, n);

	while(mul > 0) {
		if(exp) n *= 10;
		else n /= 10;
		mul--;
	}

	if(sign) n = -n;
	return n;
}
示例#3
0
文件: rrd.c 项目: 4224657/netdata
unsigned long long rrdset_done(RRDSET *st)
{
	if(unlikely(netdata_exit)) return 0;

	debug(D_RRD_CALLS, "rrdset_done() for chart %s", st->name);

	RRDDIM *rd, *last;
	int oldstate, store_this_entry = 1, first_entry = 0;
	unsigned long long last_ut, now_ut, next_ut, stored_entries = 0;

	if(unlikely(pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate) != 0))
		error("Cannot set pthread cancel state to DISABLE.");

	// a read lock is OK here
	pthread_rwlock_rdlock(&st->rwlock);

	// enable the chart, if it was disabled
	if(unlikely(rrd_delete_unupdated_dimensions) && !st->enabled)
		st->enabled = 1;

	// check if the chart has a long time to be updated
	if(unlikely(st->usec_since_last_update > st->entries * st->update_every * 1000000ULL)) {
		info("%s: took too long to be updated (%0.3Lf secs). Reseting it.", st->name, (long double)(st->usec_since_last_update / 1000000.0));
		rrdset_reset(st);
		st->usec_since_last_update = st->update_every * 1000000ULL;
		first_entry = 1;
	}
	if(unlikely(st->debug)) debug(D_RRD_STATS, "%s: microseconds since last update: %llu", st->name, st->usec_since_last_update);

	// set last_collected_time
	if(unlikely(!st->last_collected_time.tv_sec)) {
		// it is the first entry
		// set the last_collected_time to now
		gettimeofday(&st->last_collected_time, NULL);

		// the first entry should not be stored
		store_this_entry = 0;
		first_entry = 1;

		if(unlikely(st->debug)) debug(D_RRD_STATS, "%s: has not set last_collected_time. Setting it now. Will not store the next entry.", st->name);
	}
	else {
		// it is not the first entry
		// calculate the proper last_collected_time, using usec_since_last_update
		unsigned long long ut = st->last_collected_time.tv_sec * 1000000ULL + st->last_collected_time.tv_usec + st->usec_since_last_update;
		st->last_collected_time.tv_sec = (time_t) (ut / 1000000ULL);
		st->last_collected_time.tv_usec = (suseconds_t) (ut % 1000000ULL);
	}

	// if this set has not been updated in the past
	// we fake the last_update time to be = now - usec_since_last_update
	if(unlikely(!st->last_updated.tv_sec)) {
		// it has never been updated before
		// set a fake last_updated, in the past using usec_since_last_update
		unsigned long long ut = st->last_collected_time.tv_sec * 1000000ULL + st->last_collected_time.tv_usec - st->usec_since_last_update;
		st->last_updated.tv_sec = (time_t) (ut / 1000000ULL);
		st->last_updated.tv_usec = (suseconds_t) (ut % 1000000ULL);

		// the first entry should not be stored
		store_this_entry = 0;
		first_entry = 1;

		if(unlikely(st->debug)) debug(D_RRD_STATS, "%s: initializing last_updated to now - %llu microseconds (%0.3Lf). Will not store the next entry.", st->name, st->usec_since_last_update, (long double)ut/1000000.0);
	}

	// check if we will re-write the entire data set
	if(unlikely(usecdiff(&st->last_collected_time, &st->last_updated) > st->update_every * st->entries * 1000000ULL)) {
		info("%s: too old data (last updated at %ld.%ld, last collected at %ld.%ld). Reseting it. Will not store the next entry.", st->name, st->last_updated.tv_sec, st->last_updated.tv_usec, st->last_collected_time.tv_sec, st->last_collected_time.tv_usec);
		rrdset_reset(st);

		st->usec_since_last_update = st->update_every * 1000000ULL;

		gettimeofday(&st->last_collected_time, NULL);

		unsigned long long ut = st->last_collected_time.tv_sec * 1000000ULL + st->last_collected_time.tv_usec - st->usec_since_last_update;
		st->last_updated.tv_sec = (time_t) (ut / 1000000ULL);
		st->last_updated.tv_usec = (suseconds_t) (ut % 1000000ULL);

		// the first entry should not be stored
		store_this_entry = 0;
		first_entry = 1;
	}

	// these are the 3 variables that will help us in interpolation
	// last_ut = the last time we added a value to the storage
	//  now_ut = the time the current value is taken at
	// next_ut = the time of the next interpolation point
	last_ut = st->last_updated.tv_sec * 1000000ULL + st->last_updated.tv_usec;
	now_ut  = st->last_collected_time.tv_sec * 1000000ULL + st->last_collected_time.tv_usec;
	next_ut = (st->last_updated.tv_sec + st->update_every) * 1000000ULL;

	if(unlikely(!first_entry && now_ut < next_ut)) {
		if(unlikely(st->debug)) debug(D_RRD_STATS, "%s: THIS IS IN THE SAME INTERPOLATION POINT", st->name);
	}

	if(unlikely(st->debug)) {
		debug(D_RRD_STATS, "%s: last ut = %0.3Lf (last updated time)", st->name, (long double)last_ut/1000000.0);
		debug(D_RRD_STATS, "%s: now  ut = %0.3Lf (current update time)", st->name, (long double)now_ut/1000000.0);
		debug(D_RRD_STATS, "%s: next ut = %0.3Lf (next interpolation point)", st->name, (long double)next_ut/1000000.0);
	}

	if(unlikely(!st->counter_done)) {
		store_this_entry = 0;
		if(unlikely(st->debug)) debug(D_RRD_STATS, "%s: Will not store the next entry.", st->name);
	}
	st->counter_done++;

	// calculate totals and count the dimensions
	int dimensions;
	st->collected_total = 0;
	for( rd = st->dimensions, dimensions = 0 ; likely(rd) ; rd = rd->next, dimensions++ )
		if(likely(rd->updated)) st->collected_total += rd->collected_value;

	uint32_t storage_flags = SN_EXISTS;

	// process all dimensions to calculate their values
	// based on the collected figures only
	// at this stage we do not interpolate anything
	for( rd = st->dimensions ; likely(rd) ; rd = rd->next ) {

		if(unlikely(!rd->updated)) {
			rd->calculated_value = 0;
			continue;
		}

		if(unlikely(st->debug)) debug(D_RRD_STATS, "%s/%s: START "
			" last_collected_value = " COLLECTED_NUMBER_FORMAT
			" collected_value = " COLLECTED_NUMBER_FORMAT
			" last_calculated_value = " CALCULATED_NUMBER_FORMAT
			" calculated_value = " CALCULATED_NUMBER_FORMAT
			, st->id, rd->name
			, rd->last_collected_value
			, rd->collected_value
			, rd->last_calculated_value
			, rd->calculated_value
			);

		switch(rd->algorithm) {
			case RRDDIM_ABSOLUTE:
				rd->calculated_value = (calculated_number)rd->collected_value
					* (calculated_number)rd->multiplier
					/ (calculated_number)rd->divisor;

				if(unlikely(st->debug))
					debug(D_RRD_STATS, "%s/%s: CALC ABS/ABS-NO-IN "
						CALCULATED_NUMBER_FORMAT " = "
						COLLECTED_NUMBER_FORMAT
						" * " CALCULATED_NUMBER_FORMAT
						" / " CALCULATED_NUMBER_FORMAT
						, st->id, rd->name
						, rd->calculated_value
						, rd->collected_value
						, (calculated_number)rd->multiplier
						, (calculated_number)rd->divisor
						);
				break;

			case RRDDIM_PCENT_OVER_ROW_TOTAL:
				if(unlikely(!st->collected_total))
					rd->calculated_value = 0;
				else
					// the percentage of the current value
					// over the total of all dimensions
					rd->calculated_value =
					      (calculated_number)100
					    * (calculated_number)rd->collected_value
					    / (calculated_number)st->collected_total;

				if(unlikely(st->debug))
					debug(D_RRD_STATS, "%s/%s: CALC PCENT-ROW "
						CALCULATED_NUMBER_FORMAT " = 100"
						" * " COLLECTED_NUMBER_FORMAT
						" / " COLLECTED_NUMBER_FORMAT
						, st->id, rd->name
						, rd->calculated_value
						, rd->collected_value
						, st->collected_total
						);
				break;

			case RRDDIM_INCREMENTAL:
				if(unlikely(rd->counter <= 1)) {
					rd->calculated_value = 0;
					continue;
				}

				// if the new is smaller than the old (an overflow, or reset), set the old equal to the new
				// to reset the calculation (it will give zero as the calculation for this second)
				if(unlikely(rd->last_collected_value > rd->collected_value)) {
					debug(D_RRD_STATS, "%s.%s: RESET or OVERFLOW. Last collected value = " COLLECTED_NUMBER_FORMAT ", current = " COLLECTED_NUMBER_FORMAT
							, st->name, rd->name
							, rd->last_collected_value
							, rd->collected_value);
					if(!(rd->flags & RRDDIM_FLAG_DONT_DETECT_RESETS_OR_OVERFLOWS)) storage_flags = SN_EXISTS_RESET;
					rd->last_collected_value = rd->collected_value;
				}

				rd->calculated_value =
				      (calculated_number)(rd->collected_value - rd->last_collected_value)
				    * (calculated_number)rd->multiplier
				    / (calculated_number)rd->divisor;

				if(unlikely(st->debug))
					debug(D_RRD_STATS, "%s/%s: CALC INC PRE "
						CALCULATED_NUMBER_FORMAT " = ("
						COLLECTED_NUMBER_FORMAT " - " COLLECTED_NUMBER_FORMAT
						")"
						" * " CALCULATED_NUMBER_FORMAT
						" / " CALCULATED_NUMBER_FORMAT
						, st->id, rd->name
						, rd->calculated_value
						, rd->collected_value, rd->last_collected_value
						, (calculated_number)rd->multiplier
						, (calculated_number)rd->divisor
						);
				break;

			case RRDDIM_PCENT_OVER_DIFF_TOTAL:
				if(unlikely(rd->counter <= 1)) {
					rd->calculated_value = 0;
					continue;
				}

				// if the new is smaller than the old (an overflow, or reset), set the old equal to the new
				// to reset the calculation (it will give zero as the calculation for this second)
				if(unlikely(rd->last_collected_value > rd->collected_value)) {
					debug(D_RRD_STATS, "%s.%s: RESET or OVERFLOW. Last collected value = " COLLECTED_NUMBER_FORMAT ", current = " COLLECTED_NUMBER_FORMAT
					, st->name, rd->name
					, rd->last_collected_value
					, rd->collected_value);
					if(!(rd->flags & RRDDIM_FLAG_DONT_DETECT_RESETS_OR_OVERFLOWS)) storage_flags = SN_EXISTS_RESET;
					rd->last_collected_value = rd->collected_value;
				}

				// the percentage of the current increment
				// over the increment of all dimensions together
				if(unlikely(st->collected_total == st->last_collected_total))
					rd->calculated_value = 0;
				else
					rd->calculated_value =
						  (calculated_number)100
						* (calculated_number)(rd->collected_value - rd->last_collected_value)
						/ (calculated_number)(st->collected_total - st->last_collected_total);

				if(unlikely(st->debug))
					debug(D_RRD_STATS, "%s/%s: CALC PCENT-DIFF "
						CALCULATED_NUMBER_FORMAT " = 100"
						" * (" COLLECTED_NUMBER_FORMAT " - " COLLECTED_NUMBER_FORMAT ")"
						" / (" COLLECTED_NUMBER_FORMAT " - " COLLECTED_NUMBER_FORMAT ")"
						, st->id, rd->name
						, rd->calculated_value
						, rd->collected_value, rd->last_collected_value
						, st->collected_total, st->last_collected_total
						);
				break;

			default:
				// make the default zero, to make sure
				// it gets noticed when we add new types
				rd->calculated_value = 0;

				if(unlikely(st->debug))
					debug(D_RRD_STATS, "%s/%s: CALC "
						CALCULATED_NUMBER_FORMAT " = 0"
						, st->id, rd->name
						, rd->calculated_value
						);
				break;
		}

		if(unlikely(st->debug)) debug(D_RRD_STATS, "%s/%s: PHASE2 "
			" last_collected_value = " COLLECTED_NUMBER_FORMAT
			" collected_value = " COLLECTED_NUMBER_FORMAT
			" last_calculated_value = " CALCULATED_NUMBER_FORMAT
			" calculated_value = " CALCULATED_NUMBER_FORMAT
			, st->id, rd->name
			, rd->last_collected_value
			, rd->collected_value
			, rd->last_calculated_value
			, rd->calculated_value
			);

	}

	// at this point we have all the calculated values ready
	// it is now time to interpolate values on a second boundary

	unsigned long long first_ut = last_ut;
	long long iterations = (now_ut - last_ut) / (st->update_every * 1000000ULL);
	if((now_ut % (st->update_every * 1000000ULL)) == 0) iterations++;

	for( ; likely(next_ut <= now_ut) ; next_ut += st->update_every * 1000000ULL, iterations-- ) {
#ifdef NETDATA_INTERNAL_CHECKS
		if(iterations < 0) { error("%s: iterations calculation wrapped! first_ut = %llu, last_ut = %llu, next_ut = %llu, now_ut = %llu", st->name, first_ut, last_ut, next_ut, now_ut); }
#endif

		if(unlikely(st->debug)) {
			debug(D_RRD_STATS, "%s: last ut = %0.3Lf (last updated time)", st->name, (long double)last_ut/1000000.0);
			debug(D_RRD_STATS, "%s: next ut = %0.3Lf (next interpolation point)", st->name, (long double)next_ut/1000000.0);
		}

		st->last_updated.tv_sec = (time_t) (next_ut / 1000000ULL);
		st->last_updated.tv_usec = 0;

		for( rd = st->dimensions ; likely(rd) ; rd = rd->next ) {
			calculated_number new_value;

			switch(rd->algorithm) {
				case RRDDIM_INCREMENTAL:
					new_value = (calculated_number)
						(	   rd->calculated_value
							* (calculated_number)(next_ut - last_ut)
							/ (calculated_number)(now_ut - last_ut)
						);

					if(unlikely(st->debug))
						debug(D_RRD_STATS, "%s/%s: CALC2 INC "
							CALCULATED_NUMBER_FORMAT " = "
							CALCULATED_NUMBER_FORMAT
							" * %llu"
							" / %llu"
							, st->id, rd->name
							, new_value
							, rd->calculated_value
							, (next_ut - last_ut)
							, (now_ut - last_ut)
							);

					rd->calculated_value -= new_value;
					new_value += rd->last_calculated_value;
					rd->last_calculated_value = 0;
					new_value /= (calculated_number)st->update_every;
					break;

				case RRDDIM_ABSOLUTE:
				case RRDDIM_PCENT_OVER_ROW_TOTAL:
				case RRDDIM_PCENT_OVER_DIFF_TOTAL:
				default:
					if(iterations == 1) {
						// this is the last iteration
						// do not interpolate
						// just show the calculated value

						new_value = rd->calculated_value;
					}
					else {
						// we have missed an update
						// interpolate in the middle values

						new_value = (calculated_number)
							(	(	  (rd->calculated_value - rd->last_calculated_value)
									* (calculated_number)(next_ut - first_ut)
									/ (calculated_number)(now_ut - first_ut)
								)
								+  rd->last_calculated_value
							);

						if(unlikely(st->debug))
							debug(D_RRD_STATS, "%s/%s: CALC2 DEF "
								CALCULATED_NUMBER_FORMAT " = ((("
								"(" CALCULATED_NUMBER_FORMAT " - " CALCULATED_NUMBER_FORMAT ")"
								" * %llu"
								" / %llu) + " CALCULATED_NUMBER_FORMAT
								, st->id, rd->name
								, new_value
								, rd->calculated_value, rd->last_calculated_value
								, (next_ut - first_ut)
								, (now_ut - first_ut), rd->last_calculated_value
								);

						// this is wrong
						// it fades the value towards the target
						// while we know the calculated value is different
						// if(likely(next_ut + st->update_every * 1000000ULL > now_ut)) rd->calculated_value = new_value;
					}
					break;
			}

			if(unlikely(!store_this_entry)) {
				store_this_entry = 1;
				continue;
			}

			if(likely(rd->updated && rd->counter > 1 && iterations < st->gap_when_lost_iterations_above)) {
				rd->values[st->current_entry] = pack_storage_number(new_value, storage_flags );

				if(unlikely(st->debug))
					debug(D_RRD_STATS, "%s/%s: STORE[%ld] "
						CALCULATED_NUMBER_FORMAT " = " CALCULATED_NUMBER_FORMAT
						, st->id, rd->name
						, st->current_entry
						, unpack_storage_number(rd->values[st->current_entry]), new_value
						);
			}
			else {
				if(unlikely(st->debug)) debug(D_RRD_STATS, "%s/%s: STORE[%ld] = NON EXISTING "
						, st->id, rd->name
						, st->current_entry
						);
				rd->values[st->current_entry] = pack_storage_number(0, SN_NOT_EXISTS);
			}

			stored_entries++;

			if(unlikely(st->debug)) {
				calculated_number t1 = new_value * (calculated_number)rd->multiplier / (calculated_number)rd->divisor;
				calculated_number t2 = unpack_storage_number(rd->values[st->current_entry]);
				calculated_number accuracy = accuracy_loss(t1, t2);
				debug(D_RRD_STATS, "%s/%s: UNPACK[%ld] = " CALCULATED_NUMBER_FORMAT " FLAGS=0x%08x (original = " CALCULATED_NUMBER_FORMAT ", accuracy loss = " CALCULATED_NUMBER_FORMAT "%%%s)"
						, st->id, rd->name
						, st->current_entry
						, t2
						, get_storage_number_flags(rd->values[st->current_entry])
						, t1
						, accuracy
						, (accuracy > ACCURACY_LOSS) ? " **TOO BIG** " : ""
						);

				rd->collected_volume += t1;
				rd->stored_volume += t2;
				accuracy = accuracy_loss(rd->collected_volume, rd->stored_volume);
				debug(D_RRD_STATS, "%s/%s: VOLUME[%ld] = " CALCULATED_NUMBER_FORMAT ", calculated  = " CALCULATED_NUMBER_FORMAT ", accuracy loss = " CALCULATED_NUMBER_FORMAT "%%%s"
						, st->id, rd->name
						, st->current_entry
						, rd->stored_volume
						, rd->collected_volume
						, accuracy
						, (accuracy > ACCURACY_LOSS) ? " **TOO BIG** " : ""
						);

			}
		}
		// reset the storage flags for the next point, if any;
		storage_flags = SN_EXISTS;

		st->counter++;
		st->current_entry = ((st->current_entry + 1) >= st->entries) ? 0 : st->current_entry + 1;
		last_ut = next_ut;
	}

	// align next interpolation to last collection point
	if(likely(stored_entries || !store_this_entry)) {
		st->last_updated.tv_sec = st->last_collected_time.tv_sec;
		st->last_updated.tv_usec = st->last_collected_time.tv_usec;
		st->last_collected_total  = st->collected_total;
	}

	for( rd = st->dimensions; likely(rd) ; rd = rd->next ) {
		if(unlikely(!rd->updated)) continue;

		if(likely(stored_entries || !store_this_entry)) {
			if(unlikely(st->debug)) debug(D_RRD_STATS, "%s/%s: setting last_collected_value (old: " COLLECTED_NUMBER_FORMAT ") to last_collected_value (new: " COLLECTED_NUMBER_FORMAT ")", st->id, rd->name, rd->last_collected_value, rd->collected_value);
			rd->last_collected_value = rd->collected_value;

			if(unlikely(st->debug)) debug(D_RRD_STATS, "%s/%s: setting last_calculated_value (old: " CALCULATED_NUMBER_FORMAT ") to last_calculated_value (new: " CALCULATED_NUMBER_FORMAT ")", st->id, rd->name, rd->last_calculated_value, rd->calculated_value);
			rd->last_calculated_value = rd->calculated_value;
		}

		rd->calculated_value = 0;
		rd->collected_value = 0;
		rd->updated = 0;

		if(unlikely(st->debug)) debug(D_RRD_STATS, "%s/%s: END "
			" last_collected_value = " COLLECTED_NUMBER_FORMAT
			" collected_value = " COLLECTED_NUMBER_FORMAT
			" last_calculated_value = " CALCULATED_NUMBER_FORMAT
			" calculated_value = " CALCULATED_NUMBER_FORMAT
			, st->id, rd->name
			, rd->last_collected_value
			, rd->collected_value
			, rd->last_calculated_value
			, rd->calculated_value
			);
	}

	// ALL DONE ABOUT THE DATA UPDATE
	// --------------------------------------------------------------------

	// find if there are any obsolete dimensions (not updated recently)
	if(unlikely(rrd_delete_unupdated_dimensions)) {

		for( rd = st->dimensions; likely(rd) ; rd = rd->next )
			if((rd->last_collected_time.tv_sec + (rrd_delete_unupdated_dimensions * st->update_every)) < st->last_collected_time.tv_sec)
				break;

		if(unlikely(rd)) {
			// there is dimension to free
			// upgrade our read lock to a write lock
			pthread_rwlock_unlock(&st->rwlock);
			pthread_rwlock_wrlock(&st->rwlock);

			for( rd = st->dimensions, last = NULL ; likely(rd) ; ) {
				// remove it only it is not updated in rrd_delete_unupdated_dimensions seconds

				if(unlikely((rd->last_collected_time.tv_sec + (rrd_delete_unupdated_dimensions * st->update_every)) < st->last_collected_time.tv_sec)) {
					info("Removing obsolete dimension '%s' (%s) of '%s' (%s).", rd->name, rd->id, st->name, st->id);

					if(unlikely(!last)) {
						st->dimensions = rd->next;
						rd->next = NULL;
						rrddim_free(st, rd);
						rd = st->dimensions;
						continue;
					}
					else {
						last->next = rd->next;
						rd->next = NULL;
						rrddim_free(st, rd);
						rd = last->next;
						continue;
					}
				}

				last = rd;
				rd = rd->next;
			}

			if(unlikely(!st->dimensions)) {
				info("Disabling chart %s (%s) since it does not have any dimensions", st->name, st->id);
				st->enabled = 0;
			}
		}
	}

	pthread_rwlock_unlock(&st->rwlock);

	if(unlikely(pthread_setcancelstate(oldstate, NULL) != 0))
		error("Cannot set pthread cancel state to RESTORE (%d).", oldstate);

	return(st->usec_since_last_update);
}
示例#4
0
storage_number pack_storage_number(calculated_number value, uint32_t flags)
{
	// bit 32 = sign 0:positive, 1:negative
	// bit 31 = 0:divide, 1:multiply
	// bit 30, 29, 28 = (multiplier or divider) 0-6 (7 total)
	// bit 27, 26, 25 flags
	// bit 24 to bit 1 = the value

	storage_number r = get_storage_number_flags(flags);
	if(!value) return r;

	int m = 0;
	calculated_number n = value;

	// if the value is negative
	// add the sign bit and make it positive
	if(n < 0) {
		r += (1 << 31); // the sign bit 32
		n = -n;
	}

	// make its integer part fit in 0x00ffffff
	// by dividing it by 10 up to 7 times
	// and increasing the multiplier
	while(m < 7 && n > (calculated_number)0x00ffffff) {
		n /= 10;
		m++;
	}

	if(m) {
		// the value was too big and we divided it
		// so we add a multiplier to unpack it
		r += (1 << 30) + (m << 27); // the multiplier m

		if(n > (calculated_number)0x00ffffff) {
			error("Number " CALCULATED_NUMBER_FORMAT " is too big.", value);
			r += 0x00ffffff;
			return r;
		}
	}
	else {
		// 0x0019999e is the number that can be multiplied
		// by 10 to give 0x00ffffff
		// while the value is below 0x0019999e we can
		// multiply it by 10, up to 7 times, increasing
		// the multiplier
		while(m < 7 && n < (calculated_number)0x0019999e) {
			n *= 10;
			m++;
		}

		// the value was small enough and we multiplied it
		// so we add a divider to unpack it
		r += (0 << 30) + (m << 27); // the divider m
	}

#ifdef STORAGE_WITH_MATH
	// without this there are rounding problems
	// example: 0.9 becomes 0.89
	r += lrint((double) n);
#else
	r += (storage_number)n;
#endif

	return r;
}