From cf5c6bc4ae7a0ee1a956bbf9b4c9872bbe06e22c Mon Sep 17 00:00:00 2001 From: Eduardo Julian Date: Mon, 17 Apr 2017 19:55:42 -0400 Subject: - Improved the precision of (Deg)ree division. --- luxc/src/lux/compiler/js/rt.clj | 18 +++++++++++- luxc/src/lux/compiler/jvm/rt.clj | 59 ++++++++++++++++++++++++++++++++-------- 2 files changed, 65 insertions(+), 12 deletions(-) (limited to 'luxc/src') diff --git a/luxc/src/lux/compiler/js/rt.clj b/luxc/src/lux/compiler/js/rt.clj index f17998871..d5f503f01 100644 --- a/luxc/src/lux/compiler/js/rt.clj +++ b/luxc/src/lux/compiler/js/rt.clj @@ -618,8 +618,24 @@ "return LuxRT$addI64(top,bottomAndMiddle);" "})") + "countLeadingZeroes" (str "(function LuxRT$countLeadingZeroes(input) {" + "var zeroes = 64;" + (str "while(!LuxRT$eqI64(input,LuxRT$ZERO)) {" + "zeroes--;" + "input = LuxRT$ushrI64(input,1);" + "}") + "return zeroes;" + "})") "divD64" (str "(function LuxRT$divD64(l,r) {" - "return LuxRT$shlI64(LuxRT$divI64(l,LuxRT$fromNumberI64(r.H)),32);" + (str "if(LuxRT$eqI64(l,r)) {" + "return LuxRT$negateI64(LuxRT$ONE);" ;; ~= 1.0 DEG + "}" + "else {" + "var minShift = Math.min(LuxRT$countLeadingZeroes(l), LuxRT$countLeadingZeroes(r));" + "l = LuxRT$shlI64(l,minShift);" + "r = LuxRT$shlI64(r,minShift);" + "return LuxRT$shlI64(LuxRT$divI64(l,LuxRT$fromNumberI64(r.H)),32);" + "}") "})") "degToReal" (str "(function LuxRT$degToReal(input) {" "var two32 = Math.pow(2,32);" diff --git a/luxc/src/lux/compiler/jvm/rt.clj b/luxc/src/lux/compiler/jvm/rt.clj index a1b171a25..aa0c881d0 100644 --- a/luxc/src/lux/compiler/jvm/rt.clj +++ b/luxc/src/lux/compiler/jvm/rt.clj @@ -368,17 +368,54 @@ (.visitInsn Opcodes/LRETURN) (.visitMaxs 0 0) (.visitEnd)) - _ (doto (.visitMethod =class (+ Opcodes/ACC_PUBLIC Opcodes/ACC_STATIC) "div_deg" "(JJ)J" nil nil) - (.visitCode) - ;; Based on: http://stackoverflow.com/a/8510587/6823464 - (.visitVarInsn Opcodes/LLOAD 0) - (.visitVarInsn Opcodes/LLOAD 2) high-4b - (.visitInsn Opcodes/LDIV) - (.visitLdcInsn (int 32)) - (.visitInsn Opcodes/LSHL) - (.visitInsn Opcodes/LRETURN) - (.visitMaxs 0 0) - (.visitEnd)) + _ (let [$loop-start (new Label) + $done (new Label)] + (doto (.visitMethod =class (+ Opcodes/ACC_PUBLIC Opcodes/ACC_STATIC) "count_leading_zeros" "(J)I" nil nil) + (.visitCode) + (.visitLdcInsn (int 64)) + (.visitLabel $loop-start) + (.visitVarInsn Opcodes/LLOAD 0) + (.visitLdcInsn (long 0)) + (.visitInsn Opcodes/LCMP) + (.visitJumpInsn Opcodes/IFEQ $done) + (.visitVarInsn Opcodes/LLOAD 0) + (.visitLdcInsn (int 1)) + (.visitInsn Opcodes/LUSHR) + (.visitVarInsn Opcodes/LSTORE 0) + (.visitLdcInsn (int 1)) + (.visitInsn Opcodes/ISUB) + (.visitJumpInsn Opcodes/GOTO $loop-start) + (.visitLabel $done) + (.visitInsn Opcodes/IRETURN) + (.visitMaxs 0 0) + (.visitEnd))) + _ (let [$same (new Label)] + (doto (.visitMethod =class (+ Opcodes/ACC_PUBLIC Opcodes/ACC_STATIC) "div_deg" "(JJ)J" nil nil) + (.visitCode) + (.visitVarInsn Opcodes/LLOAD 0) + (.visitVarInsn Opcodes/LLOAD 2) + (.visitInsn Opcodes/LCMP) + (.visitJumpInsn Opcodes/IFEQ $same) + ;; Based on: http://stackoverflow.com/a/8510587/6823464 + ;; Shifting the operands as much as possible can help + ;; avoid some loss of precision later. + (.visitVarInsn Opcodes/LLOAD 0) + (.visitMethodInsn Opcodes/INVOKESTATIC "lux/LuxRT" "count_leading_zeros" "(J)I") + (.visitVarInsn Opcodes/LLOAD 2) + (.visitMethodInsn Opcodes/INVOKESTATIC "lux/LuxRT" "count_leading_zeros" "(J)I") + (.visitMethodInsn Opcodes/INVOKESTATIC "java/lang/Math" "min" "(II)I") + (.visitVarInsn Opcodes/ISTORE 4) + (.visitVarInsn Opcodes/LLOAD 0) (.visitVarInsn Opcodes/ILOAD 4) (.visitInsn Opcodes/LSHL) + (.visitVarInsn Opcodes/LLOAD 2) (.visitVarInsn Opcodes/ILOAD 4) (.visitInsn Opcodes/LSHL) high-4b + (.visitInsn Opcodes/LDIV) + (.visitLdcInsn (int 32)) + (.visitInsn Opcodes/LSHL) + (.visitInsn Opcodes/LRETURN) + (.visitLabel $same) + (.visitLdcInsn (long -1)) ;; ~= 1.0 DEG + (.visitInsn Opcodes/LRETURN) + (.visitMaxs 0 0) + (.visitEnd))) _ (doto (.visitMethod =class (+ Opcodes/ACC_PUBLIC Opcodes/ACC_STATIC) "deg-to-real" "(J)D" nil nil) (.visitCode) ;; Translate high bytes -- cgit v1.2.3