Index: binutils-gdb/gdb/target-float.c
===================================================================
--- binutils-gdb.orig/gdb/target-float.c
+++ binutils-gdb/gdb/target-float.c
@@ -59,6 +59,27 @@ floatformat_from_ulongest (const struct
   floatformat_from_doublest (fmt, &d, addr);
 }
 
+/* Convert the byte-stream ADDR, interpreted as floating-point format FMT,
+   to a floating-point value in the host "double" format.  */
+static double
+floatformat_to_host_double (const struct floatformat *fmt,
+			    const gdb_byte *addr)
+{
+  DOUBLEST d;
+  floatformat_to_doublest (fmt, addr, &d);
+  return (double) d;
+}
+
+/* Convert floating-point value VAL in the host "double" format to a target
+   floating-number of format FMT and store it as byte-stream ADDR.  */
+static void
+floatformat_from_host_double (const struct floatformat *fmt, gdb_byte *addr,
+			      double val)
+{
+  DOUBLEST d = (DOUBLEST) val;
+  floatformat_from_doublest (fmt, &d, addr);
+}
+
 /* Convert a floating-point number of format FROM_FMT from the target
    byte-stream FROM to a floating-point number of format TO_FMT, and
    store it to the target byte-stream TO.  */
@@ -298,6 +319,42 @@ target_float_from_ulongest (gdb_byte *ad
 
   gdb_assert_not_reached ("unexpected type code");
 }
+
+/* Convert the byte-stream ADDR, interpreted as floating-point type TYPE,
+   to a floating-point value in the host "double" format.  */
+double
+target_float_to_host_double (const gdb_byte *addr,
+			     const struct type *type)
+{
+  if (TYPE_CODE (type) == TYPE_CODE_FLT)
+    return floatformat_to_host_double (floatformat_from_type (type), addr);
+
+  /* We don't support conversions between target decimal floating-point
+     types and the host double type here.  */
+
+  gdb_assert_not_reached ("unexpected type code");
+}
+
+/* Convert floating-point value VAL in the host "double" format to a target
+   floating-number of type TYPE and store it as byte-stream ADDR.  */
+void
+target_float_from_host_double (gdb_byte *addr, const struct type *type,
+			       double val)
+{
+  /* Ensure possible padding bytes in the target buffer are zeroed out.  */
+  memset (addr, 0, TYPE_LENGTH (type));
+
+  if (TYPE_CODE (type) == TYPE_CODE_FLT)
+    {
+      floatformat_from_host_double (floatformat_from_type (type), addr, val);
+      return;
+    }
+
+  /* We don't support conversions between target decimal floating-point
+     types and the host double type here.  */
+
+  gdb_assert_not_reached ("unexpected type code");
+}
 
 /* Convert a floating-point number of type FROM_TYPE from the target
    byte-stream FROM to a floating-point number of type TO_TYPE, and
Index: binutils-gdb/gdb/target-float.h
===================================================================
--- binutils-gdb.orig/gdb/target-float.h
+++ binutils-gdb/gdb/target-float.h
@@ -42,6 +42,11 @@ extern void target_float_from_longest (g
 extern void target_float_from_ulongest (gdb_byte *addr,
 					const struct type *type,
 					ULONGEST val);
+extern double target_float_to_host_double (const gdb_byte *addr,
+					   const struct type *type);
+extern void target_float_from_host_double (gdb_byte *addr,
+					   const struct type *type,
+					   double val);
 extern void target_float_convert (const gdb_byte *from,
 				  const struct type *from_type,
 				  gdb_byte *to, const struct type *to_type);
Index: binutils-gdb/gdb/guile/scm-value.c
===================================================================
--- binutils-gdb.orig/gdb/guile/scm-value.c
+++ binutils-gdb/gdb/guile/scm-value.c
@@ -24,6 +24,7 @@
 #include "arch-utils.h"
 #include "charset.h"
 #include "cp-abi.h"
+#include "target-float.h"
 #include "infcall.h"
 #include "symtab.h" /* Needed by language.h.  */
 #include "language.h"
@@ -1019,7 +1020,8 @@ gdbscm_value_to_real (SCM self)
     = vlscm_get_value_smob_arg_unsafe (self, SCM_ARG1, FUNC_NAME);
   struct value *value = v_smob->value;
   struct type *type;
-  DOUBLEST d = 0;
+  double d = 0;
+  struct value *check = nullptr;
 
   type = value_type (value);
 
@@ -1038,7 +1040,22 @@ gdbscm_value_to_real (SCM self)
 
   TRY
     {
-      d = value_as_double (value);
+      if (is_floating_value (value))
+	{
+	  d = target_float_to_host_double (value_contents (value), type);
+	  check = allocate_value (type);
+	  target_float_from_host_double (value_contents_raw (check), type, d);
+	}
+      else if (TYPE_UNSIGNED (type))
+	{
+	  d = (ULONGEST) value_as_long (value);
+	  check = value_from_ulongest (type, (ULONGEST) d);
+	}
+      else
+	{
+	  d = value_as_long (value);
+	  check = value_from_longest (type, (LONGEST) d);
+	}
     }
   CATCH (except, RETURN_MASK_ALL)
     {
@@ -1047,7 +1064,7 @@ gdbscm_value_to_real (SCM self)
   END_CATCH
 
   /* TODO: Is there a better way to check if the value fits?  */
-  if (d != (double) d)
+  if (!value_equal (value, check))
     gdbscm_out_of_range_error (FUNC_NAME, SCM_ARG1, self,
 			       _("number can't be converted to a double"));
 
Index: binutils-gdb/gdb/guile/scm-math.c
===================================================================
--- binutils-gdb.orig/gdb/guile/scm-math.c
+++ binutils-gdb/gdb/guile/scm-math.c
@@ -24,9 +24,7 @@
 #include "arch-utils.h"
 #include "charset.h"
 #include "cp-abi.h"
-#include "doublest.h" /* Needed by dfp.h.  */
-#include "expression.h" /* Needed by dfp.h.  */
-#include "dfp.h"
+#include "target-float.h"
 #include "symtab.h" /* Needed by language.h.  */
 #include "language.h"
 #include "valprint.h"
@@ -599,7 +597,13 @@ vlscm_convert_typed_number (const char *
 	}
     }
   else if (TYPE_CODE (type) == TYPE_CODE_FLT)
-    return value_from_double (type, scm_to_double (obj));
+    {
+      struct value *value = allocate_value (type);
+      target_float_from_host_double (value_contents_raw (value),
+				     value_type (value),
+				     scm_to_double (obj));
+      return value;
+    }
   else
     {
       *except_scmp = gdbscm_make_type_error (func_name, obj_arg_pos, obj,
@@ -679,7 +683,13 @@ vlscm_convert_number (const char *func_n
 				   gdbscm_scm_to_ulongest (obj));
     }
   else if (scm_is_real (obj))
-    return value_from_double (bt->builtin_double, scm_to_double (obj));
+    {
+      struct value *value = allocate_value (bt->builtin_double);
+      target_float_from_host_double (value_contents_raw (value),
+				     value_type (value),
+				     scm_to_double (obj));
+      return value;
+    }
 
   *except_scmp = gdbscm_make_out_of_range_error (func_name, obj_arg_pos, obj,
 			_("value not a number representable on the target"));
Index: binutils-gdb/gdb/python/py-value.c
===================================================================
--- binutils-gdb.orig/gdb/python/py-value.c
+++ binutils-gdb/gdb/python/py-value.c
@@ -1560,10 +1560,10 @@ valpy_float (PyObject *self)
     {
       type = check_typedef (type);
 
-      if (TYPE_CODE (type) != TYPE_CODE_FLT)
+      if (TYPE_CODE (type) != TYPE_CODE_FLT || !is_floating_value (value))
 	error (_("Cannot convert value to float."));
 
-      d = value_as_double (value);
+      d = target_float_to_host_double (value_contents (value), type);
     }
   CATCH (except, RETURN_MASK_ALL)
     {
@@ -1681,7 +1681,11 @@ convert_value_from_python (PyObject *obj
 	  double d = PyFloat_AsDouble (obj);
 
 	  if (! PyErr_Occurred ())
-	    value = value_from_double (builtin_type_pyfloat, d);
+	    {
+	      value = allocate_value (builtin_type_pyfloat);
+	      target_float_from_host_double (value_contents_raw (value),
+					     value_type (value), d);
+	    }
 	}
       else if (gdbpy_is_string (obj))
 	{
