generate float instead of double if constraints suggest this
diff --git a/libasn1compiler/asn1c_C.c b/libasn1compiler/asn1c_C.c
index c5ededd..5800bb5 100644
--- a/libasn1compiler/asn1c_C.c
+++ b/libasn1compiler/asn1c_C.c
@@ -122,6 +122,21 @@
 	return 1;
 }
 
+static int
+REAL_fits_float32(arg_t *arg, asn1p_expr_t *expr) {
+	asn1p_expr_type_e etype = expr_get_type(arg, arg->expr);
+    if(etype == ASN_BASIC_REAL) {
+        asn1cnst_range_t *range = asn1constraint_compute_OER_range(
+            expr->Identifier, etype, expr->combined_constraints, ACT_EL_RANGE,
+            0, 0, 0);
+        int fits = range->narrowing == NARROW_FLOAT32;
+        asn1constraint_range_free(range);
+        return fits;
+    } else {
+        return 0;
+    }
+}
+
 int
 asn1c_lang_C_type_common_INTEGER(arg_t *arg) {
 	asn1p_expr_t *expr = arg->expr;
@@ -1298,6 +1313,7 @@
 		&& expr_elements_count(arg, expr))
 	|| (expr->expr_type == ASN_BASIC_INTEGER
 		&& asn1c_type_fits_long(arg, expr) == FL_FITS_UNSIGN)
+	|| REAL_fits_float32(arg, expr)
 	)
 		etd_spec = ETD_HAS_SPECIFICS;
 	else
@@ -1339,6 +1355,16 @@
 
 	REDIR(OT_STAT_DEFS);
 
+	if(REAL_fits_float32(arg, expr)) {
+		if(!(expr->_type_referenced)) OUT("static ");
+		OUT("const asn_NativeReal_specifics_t asn_SPC_%s_specs_%d = {\n",
+			MKID(expr), expr->_type_unique_index);
+		INDENT(+1);
+		OUT("4\t/* Use 'float' type. */\n");
+		INDENT(-1);
+		OUT("};\n");
+	}
+
 	/*
 	 * Print out asn_DEF_<type>_[all_]tags[] vectors.
 	 */
@@ -1374,22 +1400,22 @@
 			p, expr->_type_unique_index);
 	} else {
 		OUT("extern asn_TYPE_descriptor_t asn_DEF_%s;\n", p);
-		if (etd_spec == ETD_HAS_SPECIFICS) {
-			if((expr->expr_type == ASN_BASIC_ENUMERATED) ||
-				(expr->expr_type == ASN_BASIC_INTEGER)) {
-				if(expr->_type_referenced) {
-					OUT("extern const asn_INTEGER_specifics_t "
-						"asn_SPC_%s_specs_%d;\n", c_name(arg).base_name, expr->_type_unique_index);
-				}
-			} else {
+        if(etd_spec == ETD_HAS_SPECIFICS && expr->_type_referenced) {
+            if((expr->expr_type == ASN_BASIC_ENUMERATED)
+               || (expr->expr_type == ASN_BASIC_INTEGER)) {
+                OUT("extern const asn_INTEGER_specifics_t "
+                    "asn_SPC_%s_specs_%d;\n",
+                    c_name(arg).base_name, expr->_type_unique_index);
+            } else {
                 asn1p_expr_t *terminal = WITH_MODULE_NAMESPACE(
                     expr->module, expr_ns,
                     asn1f_find_terminal_type_ex(arg->asn, expr_ns, expr));
-
-                OUT("extern asn_%s_specifics_t ", asn1c_type_name(arg, terminal, TNF_SAFE));
-				OUT("asn_SPC_%s_specs_%d;\n", MKID(expr), expr->_type_unique_index);
-			}
-		}
+                OUT("extern const asn_%s_specifics_t ",
+                    asn1c_type_name(arg, terminal, TNF_SAFE));
+                OUT("asn_SPC_%s_specs_%d;\n", MKID(expr),
+                    expr->_type_unique_index);
+            }
+        }
 		OUT("asn_struct_free_f %s_free;\n", p);
 		OUT("asn_struct_print_f %s_print;\n", p);
 		OUT("asn_constr_check_f %s_constraint;\n", p);
@@ -1846,14 +1872,6 @@
 
 	if(range->incompatible || range->not_OER_visible) {
 		OUT("{ 0, 0 }");
-    } else if(expr_get_type(arg, arg->expr) == ASN_BASIC_REAL) {
-        if(range->narrowing == NARROW_FLOAT32) {
-            OUT("{ 4, 0 }");
-        } else if(range->narrowing == NARROW_FLOAT64) {
-            OUT("{ 8, 0 }");
-        } else {
-            OUT("{ 0, 0 }");
-        }
     } else if(range->left.type == ARE_VALUE && range->left.value >= 0
               && range->right.type == ARE_MAX) {
         OUT("{ 0, 1 }");
diff --git a/libasn1compiler/asn1c_constraint.c b/libasn1compiler/asn1c_constraint.c
index d68e9d1..bd025d5 100644
--- a/libasn1compiler/asn1c_constraint.c
+++ b/libasn1compiler/asn1c_constraint.c
@@ -2,6 +2,7 @@
 #include "asn1c_constraint.h"
 #include "asn1c_misc.h"
 #include "asn1c_out.h"
+#include "asn1c_naming.h"
 
 #include <asn1fix_crange.h>	/* constraint groker from libasn1fix */
 #include <asn1fix_export.h>	/* other exportables from libasn1fix */
@@ -114,7 +115,7 @@
 				}
 				break;
 			case ASN_BASIC_REAL:
-				OUT("double value;\n");
+				OUT("%s value;\n", c_name(arg).type.constrained_c_name);
 				break;
 			case ASN_BASIC_BOOLEAN:
 				OUT("BOOLEAN_t value;\n");
@@ -676,7 +677,7 @@
 				INDENT(-1);
 			OUT("}\n");
 		} else {
-			OUT("value = *(const double *)sptr;\n");
+			OUT("value = *(const %s *)sptr;\n", c_name(arg).type.c_name);
 		}
 		break;
 	case ASN_BASIC_BOOLEAN:
diff --git a/libasn1compiler/asn1c_misc.c b/libasn1compiler/asn1c_misc.c
index 59cb497..086a8fa 100644
--- a/libasn1compiler/asn1c_misc.c
+++ b/libasn1compiler/asn1c_misc.c
@@ -215,7 +215,7 @@
 			}
 		}
 
-		if(_format == TNF_CTYPE) {
+		if(_format == TNF_CTYPE || _format == TNF_CONSTYPE) {
 			/*
 			 * If the component references the type itself,
 			 * switch to a recursion-safe type naming
@@ -236,18 +236,36 @@
 	case ASN_BASIC_ENUMERATED:
 	case ASN_BASIC_REAL:
 		if((expr->expr_type == ASN_BASIC_REAL
-			&& !(arg->flags & A1C_USE_WIDE_TYPES))
+			&& (_format == TNF_CONSTYPE || !(arg->flags & A1C_USE_WIDE_TYPES)))
 		|| asn1c_type_fits_long(arg, expr)) {
 			switch(_format) {
-			case TNF_CTYPE:
-			case TNF_RSAFE:
-				if(expr->expr_type == ASN_BASIC_REAL)
-					return "double";
-				else if(asn1c_type_fits_long(arg, expr) == FL_FITS_UNSIGN)
-					return "unsigned long";
-				else
-					return "long";
-			default:
+			case TNF_CONSTYPE:
+				if(expr->expr_type == ASN_BASIC_REAL) {
+                    return "double";
+                } else if(asn1c_type_fits_long(arg, expr) == FL_FITS_UNSIGN) {
+                    return "unsigned long";
+                } else {
+                    return "long";
+                }
+            case TNF_CTYPE:
+            case TNF_RSAFE:
+                if(expr->expr_type == ASN_BASIC_REAL) {
+                    asn1cnst_range_t *range = asn1constraint_compute_OER_range(
+                        expr->Identifier, ASN_BASIC_REAL,
+                        expr->combined_constraints, ACT_EL_RANGE, 0, 0, 0);
+                    if(range->narrowing == NARROW_FLOAT32) {
+                        asn1constraint_range_free(range);
+                        return "float";
+                    } else {
+                        asn1constraint_range_free(range);
+                        return "double";
+                    }
+                } else if(asn1c_type_fits_long(arg, expr) == FL_FITS_UNSIGN) {
+                    return "unsigned long";
+                } else {
+                    return "long";
+                }
+            default:
 				typename = 0;
 				switch(expr->expr_type) {
 				case ASN_BASIC_INTEGER:
@@ -298,6 +316,7 @@
 	case TNF_SAFE:
 		return asn1c_make_identifier(0, exprid, typename, (char*)0);
 	case TNF_CTYPE:	/* C type */
+	case TNF_CONSTYPE:	/* C type */
 		return asn1c_make_identifier(0, exprid,
 				exprid?"t":typename, exprid?0:"t", (char*)0);
 	case TNF_RSAFE:	/* Recursion-safe type */
diff --git a/libasn1compiler/asn1c_misc.h b/libasn1compiler/asn1c_misc.h
index f9f3c45..77e3827 100644
--- a/libasn1compiler/asn1c_misc.h
+++ b/libasn1compiler/asn1c_misc.h
@@ -23,8 +23,9 @@
 	TNF_UNMODIFIED	= 0x10,	/* Return unmodified type name */
 	TNF_INCLUDE	= 0x20,	/* Format for #include <> */
 	TNF_CTYPE	= 0x30,	/* Format as normal C-ish type (append "_t") */
-	TNF_SAFE	= 0x40, /* Replace unsafe characters with _ */
-	TNF_RSAFE	= 0x50,	/* Recursion-safe C type format */
+	TNF_CONSTYPE = 0x40, /* Replace unsafe characters with _ */
+	TNF_SAFE	= 0x50, /* Replace unsafe characters with _ */
+	TNF_RSAFE	= 0x60,	/* Recursion-safe C type format */
 };
 const char *asn1c_type_name(arg_t *arg, asn1p_expr_t *expr, enum tnfmt _format);
 
diff --git a/libasn1compiler/asn1c_naming.c b/libasn1compiler/asn1c_naming.c
index 82f8db5..6fad84d 100644
--- a/libasn1compiler/asn1c_naming.c
+++ b/libasn1compiler/asn1c_naming.c
@@ -121,6 +121,7 @@
     static abuf b_type_part_name;
     static abuf b_type_base_name;
     static abuf b_type_c_name;
+    static abuf b_type_constrained_c_name;
     static abuf b_asn_name;
     static abuf b_part_name;
     static abuf b_base_name;
@@ -136,6 +137,7 @@
     abuf_clear(&b_type_part_name);
     abuf_clear(&b_type_base_name);
     abuf_clear(&b_type_c_name);
+    abuf_clear(&b_type_constrained_c_name);
     abuf_clear(&b_asn_name);
     abuf_clear(&b_base_name);
     abuf_clear(&b_part_name);
@@ -152,6 +154,8 @@
     abuf_str(&b_type_part_name, asn1c_type_name(arg, expr, TNF_SAFE));
     abuf_str(&b_type_base_name, asn1c_type_name(arg, expr, TNF_SAFE));
     abuf_str(&b_type_c_name, asn1c_type_name(arg, expr, TNF_CTYPE));
+    abuf_str(&b_type_constrained_c_name,
+             asn1c_type_name(arg, expr, TNF_CONSTYPE));
 
 
     if((arg->flags & A1C_COMPOUND_NAMES)) {
@@ -189,6 +193,7 @@
     names.type.base_name = b_type_base_name.buffer;
     names.type.part_name = b_type_part_name.buffer;
     names.type.c_name = b_type_c_name.buffer;
+    names.type.constrained_c_name = b_type_constrained_c_name.buffer;
     names.asn_name = b_asn_name.buffer;
     names.part_name = b_part_name.buffer;
     names.base_name = b_base_name.buffer;
@@ -269,6 +274,7 @@
     FMT_COMPONENT(type.part_name);
     FMT_COMPONENT(type.base_name);
     FMT_COMPONENT(type.c_name);
+    FMT_COMPONENT(type.constrained_c_name);
     FMT_COMPONENT(asn_name);
     FMT_COMPONENT(part_name);
     FMT_COMPONENT(base_name);
diff --git a/libasn1compiler/asn1c_naming.h b/libasn1compiler/asn1c_naming.h
index f92431b..77af5d5 100644
--- a/libasn1compiler/asn1c_naming.h
+++ b/libasn1compiler/asn1c_naming.h
@@ -11,6 +11,7 @@
         const char *part_name;      /* "T_Rex" */
         const char *base_name;      /* "T_Rex" */
         const char *c_name;         /* "T_Rex_t" */
+        const char *constrained_c_name; /* "long" */
     } type;
     const char *asn_name;      /* "foo" */
     const char *part_name;     /* "foo", "signed" */