Check binary encodings of a Real value
diff --git a/skeletons/tests/check-REAL.c b/skeletons/tests/check-REAL.c
index db418f0..adad56e 100644
--- a/skeletons/tests/check-REAL.c
+++ b/skeletons/tests/check-REAL.c
@@ -172,9 +172,7 @@
 	 */
 	rn.buf = inbuf;
 	rn.size = insize;
-printf("%03d %f === %s %s\n", lineno, d, sample, canonical_sample);
 	asn_REAL2double(&rn, &val);
-printf("%03d %f/%f %s %s\n", lineno, val, d, sample, canonical_sample);
 	if(isnan(val)) assert(isnan(d));
 	if(isnan(d)) assert(isnan(val));
 	if(!isnan(val) && !isnan(d)) {
@@ -188,15 +186,6 @@
 	memset(&rn, 0, sizeof(rn));
 	ret = asn_double2REAL(&rn, d);
 	assert(ret == 0);
-	uint8_t *p, *end;
-	printf("received as:   [");
-	for(p = rn.buf, end = p + rn.size; p < end; p++)
-		printf("%02x", *p);
-	printf("]\n");
-	printf("received as:   [");
-	for(p = outbuf, end = p + outsize; p < end; p++)
-		printf("%02x", *p);
-	printf("]\n");
 	if(rn.size != outsize) {
 		printf("Encoded %f into %d expected %ld\n",
 			d, (int)rn.size, outsize);
@@ -248,6 +237,103 @@
 	check_str_representation(val, sample, canonical_sample, lineno);
 }
 
+/*
+ * 8.5.7 Verify binary encoding, two-way.
+ */
+static void
+check_ber_857_encoding(int base, int sign, int scaling_factor, int exponent, int mantissa) {
+	uint8_t buf[100];
+	uint8_t *b = buf;
+	int explen, mantlen;
+	REAL_t rn;
+	static REAL_t rn_check;
+	double d;
+	double verify;
+	int baseF = 0;
+	int ret;
+
+#define	BIT(b)	(1<<(b - 1))
+
+	switch(base) {
+	case 0: baseF = 1; break;
+	case 1: baseF = 3; break;
+	case 2: baseF = 4; break;
+	default: assert(base >= 0 && base <= 2);
+	}
+
+	if(exponent >= -128 && exponent <= 127) {
+		explen = 1;
+	} else {
+		assert(exponent > -60000 && exponent < 60000);
+		explen = 2;
+	}
+
+	if(mantissa == 0) {
+		mantlen = 0;
+	} else if(mantissa >= 0 && mantissa <= 255) {
+		mantlen = 1;
+	} else if(mantissa >= 0 && mantissa <= 65535) {
+		mantlen = 2;
+	} else {
+		assert(mantissa >= 0 && mantissa <= 256 * 65536);
+		mantlen = 3;
+	}
+
+	*b = BIT(8) | (sign ? BIT(7) : 0);
+	*b |= (base & 0x03) << 4;	/* 8.5.7.2 */
+	*b |= (scaling_factor & 0x03) << 2;	/* 8.5.7.3 */
+	*b |= ((explen - 1) & 0x03);	/* 8.5.7.4 */
+	b++;
+	switch(explen) {
+	case 2: *b++ = (int8_t)(exponent >> 8);
+	case 1: *b++ = (int8_t)exponent;
+	}
+	switch(mantlen) {
+	case 3: *b++ = (mantissa >> 16) & 0xff;
+	case 2: *b++ = (mantissa >> 8) & 0xff;
+	case 1: *b++ = (mantissa & 0xff);
+	}
+
+	verify = (sign ? -1.0 : 1.0) * ldexp(mantissa, exponent * baseF + scaling_factor);
+
+	/* Verify than encoding of this double value round-trips */
+	if(!isinf(verify)) {
+		d = verify;
+		verify = 0.0;
+		ret = asn_double2REAL(&rn_check, d);
+		assert(ret == 0);
+		ret = asn_REAL2double(&rn_check, &verify);
+		assert(ret == 0);
+		assert(d == verify);
+
+		/* Verify with a slight non-friendly offset. Not too easy. */
+		d = verify - 0.13;
+		verify = 0.0;
+		ret = asn_double2REAL(&rn_check, d);
+		assert(ret == 0);
+		ret = asn_REAL2double(&rn_check, &verify);
+		assert(ret == 0);
+		assert(ret == 0);
+		assert(d == verify);
+	}
+
+	verify = (sign ? -1.0 : 1.0) * ldexp(mantissa, exponent * baseF + scaling_factor);
+
+	rn.buf = buf;
+	rn.size = b - buf;
+	ret = asn_REAL2double(&rn, &d);
+	if(!isinf(verify) && (ret != 0 || d != verify)) {
+		printf("Converting B=%d, S=%d, F=%d, E=%d/%d, M=%d/%d\n", (1 << baseF), sign, scaling_factor, exponent, explen, mantissa, mantlen);
+		printf("Verify: %e\n", verify);
+		uint8_t *p;
+		printf("received as:   [");
+		for(p = buf; p < b; p++) printf("%02x", *p);
+		printf("]\n");
+		assert(ret == 0);
+		printf("Converted: %e\n", d);
+		assert(d == verify);
+	}
+}
 
 static void
 check_ber_encoding() {
@@ -483,6 +569,23 @@
   } /* for(comma symbol) */
  }
 
+  /* Scan through the range of bits, construct the valid base-2 numbers, and
+   * try two-way conversion with them */
+ {
+  int base, sign, scaling_factor, exponent, mantissa;
+  for(base = 0; base <= 2; base++) {
+    for(sign = 0; sign <= 1; sign++) {
+      for(scaling_factor = 0; scaling_factor <= 3; scaling_factor++) {
+        for(exponent = -1000; exponent < 1000; exponent += (exponent > -990 && exponent < 990) ? 100 : 1) {
+          for(mantissa = 0; mantissa < 66000; mantissa += (mantissa > 300 && mantissa < 65400) ? 100 : 1) {
+            check_ber_857_encoding(base, sign, scaling_factor, exponent, mantissa);
+          }
+	}
+      }
+    }
+  }
+ }
+
 	{
 	uint8_t b_1_0[] =
 		{ 0x80, 0xcc, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };