diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 3786099..1df4356 100644
*** a/doc/src/sgml/func.sgml
--- b/doc/src/sgml/func.sgml
***************
*** 1136,1146 ****
     </table>
  
    <para>
!    The characteristics of the values returned by
!    <literal><function>random()</function></literal> depend
!    on the system implementation. It is not suitable for cryptographic
!    applications; see <xref linkend="pgcrypto"/> module for an alternative.
!    </para>
  
    <para>
     Finally, <xref linkend="functions-math-trig-table"/> shows the
--- 1136,1150 ----
     </table>
  
    <para>
!    The <function>random()</function> function uses a simple linear
!    congruential algorithm.  It is fast but not suitable for cryptographic
!    applications; see the <xref linkend="pgcrypto"/> module for an
!    alternative.
!    If <function>setseed()</function> is called, the results of
!    subsequent <function>random()</function> calls in the current session are
!    repeatable by re-issuing <function>setseed()</function> with the same
!    argument.
!   </para>
  
    <para>
     Finally, <xref linkend="functions-math-trig-table"/> shows the
diff --git a/src/backend/utils/adt/float.c b/src/backend/utils/adt/float.c
index cf9327f..add099e 100644
*** a/src/backend/utils/adt/float.c
--- b/src/backend/utils/adt/float.c
***************
*** 22,31 ****
--- 22,34 ----
  #include "catalog/pg_type.h"
  #include "common/int.h"
  #include "libpq/pqformat.h"
+ #include "miscadmin.h"
  #include "utils/array.h"
+ #include "utils/backend_random.h"
  #include "utils/float.h"
  #include "utils/fmgrprotos.h"
  #include "utils/sortsupport.h"
+ #include "utils/timestamp.h"
  
  
  /* Configurable GUC parameter */
*************** float8		degree_c_sixty = 60.0;
*** 53,58 ****
--- 56,65 ----
  float8		degree_c_one_half = 0.5;
  float8		degree_c_one = 1.0;
  
+ /* State for drandom() and setseed() */
+ static bool drandom_seed_set = false;
+ static unsigned short drandom_seed[3] = {0, 0, 0};
+ 
  /* Local function prototypes */
  static double sind_q1(double x);
  static double cosd_q1(double x);
*************** drandom(PG_FUNCTION_ARGS)
*** 2378,2385 ****
  {
  	float8		result;
  
! 	/* result [0.0 - 1.0) */
! 	result = (double) random() / ((double) MAX_RANDOM_VALUE + 1);
  
  	PG_RETURN_FLOAT8(result);
  }
--- 2385,2414 ----
  {
  	float8		result;
  
! 	/* Initialize random seed, if not done yet in this process */
! 	if (unlikely(!drandom_seed_set))
! 	{
! 		/*
! 		 * If possible, initialize the seed using high-quality random bits.
! 		 * Should that fail for some reason, we fall back on a lower-quality
! 		 * seed based on current time and PID.
! 		 */
! 		if (!pg_backend_random((char *) drandom_seed, sizeof(drandom_seed)))
! 		{
! 			TimestampTz now = GetCurrentTimestamp();
! 			uint64		iseed;
! 
! 			/* Mix the PID with the most predictable bits of the timestamp */
! 			iseed = (uint64) now ^ ((uint64) MyProcPid << 32);
! 			drandom_seed[0] = (unsigned short) iseed;
! 			drandom_seed[1] = (unsigned short) (iseed >> 16);
! 			drandom_seed[2] = (unsigned short) (iseed >> 32);
! 		}
! 		drandom_seed_set = true;
! 	}
! 
! 	/* pg_erand48 produces desired result range [0.0 - 1.0) */
! 	result = pg_erand48(drandom_seed);
  
  	PG_RETURN_FLOAT8(result);
  }
*************** Datum
*** 2392,2404 ****
  setseed(PG_FUNCTION_ARGS)
  {
  	float8		seed = PG_GETARG_FLOAT8(0);
! 	int			iseed;
  
! 	if (seed < -1 || seed > 1)
! 		elog(ERROR, "setseed parameter %f out of range [-1,1]", seed);
  
! 	iseed = (int) (seed * MAX_RANDOM_VALUE);
! 	srandom((unsigned int) iseed);
  
  	PG_RETURN_VOID();
  }
--- 2421,2440 ----
  setseed(PG_FUNCTION_ARGS)
  {
  	float8		seed = PG_GETARG_FLOAT8(0);
! 	uint64		iseed;
  
! 	if (seed < -1 || seed > 1 || isnan(seed))
! 		ereport(ERROR,
! 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
! 				 errmsg("setseed parameter %g is out of allowed range [-1,1]",
! 						seed)));
  
! 	/* Use sign bit + 47 fractional bits to fill drandom_seed[] */
! 	iseed = (int64) (seed * (float8) UINT64CONST(0x7FFFFFFFFFFF));
! 	drandom_seed[0] = (unsigned short) iseed;
! 	drandom_seed[1] = (unsigned short) (iseed >> 16);
! 	drandom_seed[2] = (unsigned short) (iseed >> 32);
! 	drandom_seed_set = true;
  
  	PG_RETURN_VOID();
  }
