diff --git a/src/bignum.h b/src/bignum.h
index 4e4f326216ebc3f2e8486a790bd14f5305acb65a..cfbb024625928ba3860263777c4a553859ad685a 100644
--- a/src/bignum.h
+++ b/src/bignum.h
@@ -167,6 +167,16 @@ static INLINE int type ## _SUB_OVERFLOW(type a, type b) {			    \
     int of = 0;									    \
     DO_ ## type ## _SUB_OVERFLOW(a, b, &of);					    \
     return of;									    \
+}										    \
+static INLINE int type ## _MOD_OVERFLOW(type a, type b) {			    \
+    return type ## _DIV_OVERFLOW(a, b);						    \
+}										    \
+static INLINE type DO_ ## type ## _MOD_OVERFLOW(type a, type b, int * of) {	    \
+    if (type ## _MOD_OVERFLOW(a, b)) {						    \
+	*of = 1;								    \
+	return 0;								    \
+    }										    \
+    return a % b;								    \
 }
 
 
diff --git a/src/operators.c b/src/operators.c
index 7f94cb370ecc2c91408fe75bcbcf33c8d67ef9cf..32f1ca487b2aae391468d009fc7559cbf6b73f2b 100644
--- a/src/operators.c
+++ b/src/operators.c
@@ -4231,6 +4231,9 @@ PMOD_EXPORT void o_mod(void)
 {
   if(TYPEOF(sp[-2]) != TYPEOF(sp[-1]) && !float_promote())
   {
+#ifdef AUTO_BIGNUM
+do_lfun_modulo:
+#endif
     if(call_lfun(LFUN_MOD, LFUN_RMOD))
       return;
 
@@ -4305,28 +4308,49 @@ PMOD_EXPORT void o_mod(void)
     return;
   }
   case T_INT:
-    if (sp[-1].u.integer == 0)
+  {
+    int of = 0;
+    INT_TYPE a = sp[-2].u.integer,
+	     b = sp[-1].u.integer;
+    INT_TYPE res;
+    if (b == 0)
       OP_MODULO_BY_ZERO_ERROR("`%");
-    sp--;
-    if(sp[-1].u.integer>=0)
+    if(a>=0)
     {
-      if(sp[0].u.integer>=0)
+      if(b>=0)
       {
-	sp[-1].u.integer %= sp[0].u.integer;
+	res = a % b;
       }else{
-	sp[-1].u.integer=((sp[-1].u.integer+~sp[0].u.integer)%-sp[0].u.integer)-~sp[0].u.integer;
+	/* res = ((a+~b)%-b)-~b */
+	res = DO_INT_TYPE_ADD_OVERFLOW(a, ~b, &of);
+	res = DO_INT_TYPE_MOD_OVERFLOW(res, b, &of);
+	res = DO_INT_TYPE_SUB_OVERFLOW(res, ~b, &of);
       }
     }else{
-      if(sp[0].u.integer>=0)
+      if(b>=0)
       {
-	sp[-1].u.integer=sp[0].u.integer+~((~sp[-1].u.integer) % sp[0].u.integer);
+	/* res = b+~((~a) % b) */
+	res = DO_INT_TYPE_MOD_OVERFLOW(~a, b, &of);
+	res = DO_INT_TYPE_ADD_OVERFLOW(b, ~res, &of);
       }else{
-	sp[-1].u.integer=-(-sp[-1].u.integer % -sp[0].u.integer);
+	/* a % b and a % -b are equivalent, if overflow does not
+	 * happen
+	 * res = -(-a % -b) = a % b; */
+	res = DO_INT_TYPE_MOD_OVERFLOW(a, b, &of);
       }
     }
-    SET_SVAL_SUBTYPE(sp[-1], NUMBER_NUMBER);
+#ifdef AUTO_BIGNUM
+    if (of) {
+      stack_swap();
+      convert_stack_top_to_bignum();
+      stack_swap();
+      goto do_lfun_modulo;
+    }
+#endif
+    sp--;
+    SET_SVAL(sp[-1], T_INT, NUMBER_NUMBER, integer, res);
     return;
-
+  }
   default:
     PIKE_ERROR("`%", "Bad argument 1.\n", sp, 2);
   }
diff --git a/src/testsuite.in b/src/testsuite.in
index f03d6f84fa827355194ad71354190affc1028714..e6a656d430858ba319cf09d3d1a70f7c38105a3e 100644
--- a/src/testsuite.in
+++ b/src/testsuite.in
@@ -8374,6 +8374,8 @@ test_eq(0 ? "a" : 0 ? "b" : 1 ? "c" : 1, "c")
 
 // testing overflow checks
 test_eq(-1 - 0x7fffffff, -0x80000000)
+test_eq(Int.NATIVE_MIN % -1, 0)
+test_eq(Int.NATIVE_MAX % Int.NATIVE_MIN, -1)
 
 // testing indexing
 test_eq("foo"[0],'f')