test-round.c 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. /* Copyright (C) 2004, 2006, 2008 Free Software Foundation, Inc.
  2. *
  3. * This library is free software; you can redistribute it and/or
  4. * modify it under the terms of the GNU Lesser General Public
  5. * License as published by the Free Software Foundation; either
  6. * version 2.1 of the License, or (at your option) any later version.
  7. *
  8. * This library is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. * Lesser General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU Lesser General Public
  14. * License along with this library; if not, write to the Free Software
  15. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  16. */
  17. #if HAVE_CONFIG_H
  18. # include <config.h>
  19. #endif
  20. #include <assert.h>
  21. #include <math.h>
  22. #include <stdio.h>
  23. #if HAVE_FENV_H
  24. #include <fenv.h>
  25. #endif
  26. #include <libguile.h>
  27. #define numberof(x) (sizeof (x) / sizeof ((x)[0]))
  28. static void
  29. test_scm_c_round ()
  30. {
  31. /* FE constants are defined only where supported, in particular for
  32. instance some ARM systems have been seen with only a couple of modes */
  33. static const int modes[] = {
  34. 0,
  35. #ifdef FE_TONEAREST
  36. FE_TONEAREST,
  37. #endif
  38. #ifdef FE_UPWARD
  39. FE_UPWARD,
  40. #endif
  41. #ifdef FE_DOWNWARD
  42. FE_DOWNWARD,
  43. #endif
  44. #ifdef FE_TOWARDZERO
  45. FE_TOWARDZERO,
  46. #endif
  47. };
  48. double x, want;
  49. int i;
  50. for (i = 0; i < numberof (modes); i++)
  51. {
  52. /* First iteration is the default rounding mode, ie. no call to
  53. fesetround. Subsequent iterations are the FE modes from the
  54. table. */
  55. if (i != 0)
  56. {
  57. #if HAVE_FESETROUND
  58. fesetround (modes[i]);
  59. #endif
  60. }
  61. assert (scm_c_round (0.0) == 0.0);
  62. assert (scm_c_round (1.0) == 1.0);
  63. assert (scm_c_round (-1.0) == -1.0);
  64. assert (scm_c_round (0.5) == 0.0);
  65. assert (scm_c_round (1.5) == 2.0);
  66. assert (scm_c_round (-1.5) == -2.0);
  67. assert (scm_c_round (2.5) == 2.0);
  68. assert (scm_c_round (-2.5) == -2.0);
  69. assert (scm_c_round (3.5) == 4.0);
  70. assert (scm_c_round (-3.5) == -4.0);
  71. /* 2^(DBL_MANT_DIG-1)-1+0.5 */
  72. x = ldexp (1.0, DBL_MANT_DIG - 1) - 1.0 + 0.5;
  73. want = ldexp (1.0, DBL_MANT_DIG - 1);
  74. assert (scm_c_round (x) == want);
  75. /* -(2^(DBL_MANT_DIG-1)-1+0.5) */
  76. x = - (ldexp (1.0, DBL_MANT_DIG - 1) - 1.0 + 0.5);
  77. want = - ldexp (1.0, DBL_MANT_DIG - 1);
  78. assert (scm_c_round (x) == want);
  79. /* 2^DBL_MANT_DIG-1
  80. In the past scm_c_round had incorrectly incremented this value, due
  81. to the way that x+0.5 would round upwards (in the usual default
  82. nearest-even mode on most systems). */
  83. x = ldexp (1.0, DBL_MANT_DIG) - 1.0;
  84. assert (x == floor (x)); /* should be an integer already */
  85. assert (scm_c_round (x) == x); /* scm_c_round should return it unchanged */
  86. /* -(2^DBL_MANT_DIG-1) */
  87. x = - (ldexp (1.0, DBL_MANT_DIG) - 1.0);
  88. assert (x == floor (x)); /* should be an integer already */
  89. assert (scm_c_round (x) == x); /* scm_c_round should return it unchanged */
  90. /* 2^64 */
  91. x = ldexp (1.0, 64);
  92. assert (scm_c_round (x) == x);
  93. /* -2^64
  94. In the past scm_c_round had incorrectely gone to the next highest
  95. representable value in FE_UPWARD, due to x+0.5 rounding. */
  96. x = - ldexp (1.0, 64);
  97. assert (scm_c_round (x) == x);
  98. }
  99. }
  100. static void
  101. tests (void *data, int argc, char **argv)
  102. {
  103. test_scm_c_round ();
  104. }
  105. int
  106. main (int argc, char *argv[])
  107. {
  108. scm_boot_guile (argc, argv, tests, NULL);
  109. return 0;
  110. }