// The following is adapted from fdlibm (http://www.netlib.org/fdlibm).
//
// ====================================================
// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
//
// Developed at SunSoft, a Sun Microsystems, Inc. business.
// Permission to use, copy, modify, and distribute this
// software is freely granted, provided that this notice
// is preserved.
// ====================================================
//
// The original source code covered by the above license has been modified
// significantly by Google Inc.
// Copyright 2016 the V8 project authors. All rights reserved.
// Copyright (c) 2026 The elk-go Authors.
//
// The V8-derived portions are licensed under the BSD 3-Clause License; see
// LICENSE.v8-bsd. The fdlibm-derived portions retain the SunPro notice above.
//
// SPDX-License-Identifier: SunPro AND BSD-3-Clause

package javacompat

import 

// JSMathSin and JSMathCos reproduce the fdlibm implementation used by V8's
// Math.sin and Math.cos for the medium-size arguments emitted by ELK Radial.
// The kernels and constants are adapted from Node.js v24.19.0's pinned V8
// deps/v8/src/base/ieee754.cc (itself adapted from fdlibm). Very large
// arguments fall back to Go's math package; layout angles are many orders of
// magnitude below that boundary.
func ( float64) float64 {
	 := highWord() & 0x7fffffff
	if  <= 0x3fe921fb {
		return jsKernelSin(, 0, false)
	}
	if  >= 0x7ff00000 {
		return  - 
	}
	, , ,  := jsRemPiOverTwo()
	if ! {
		return math.Sin()
	}
	switch  & 3 {
	case 0:
		return jsKernelSin(, , true)
	case 1:
		return jsKernelCos(, )
	case 2:
		return -jsKernelSin(, , true)
	default:
		return -jsKernelCos(, )
	}
}

func ( float64) float64 {
	 := highWord() & 0x7fffffff
	if  <= 0x3fe921fb {
		return jsKernelCos(, 0)
	}
	if  >= 0x7ff00000 {
		return  - 
	}
	, , ,  := jsRemPiOverTwo()
	if ! {
		return math.Cos()
	}
	switch  & 3 {
	case 0:
		return jsKernelCos(, )
	case 1:
		return -jsKernelSin(, , true)
	case 2:
		return -jsKernelCos(, )
	default:
		return jsKernelSin(, , true)
	}
}

func jsRemPiOverTwo( float64) (int32, float64, float64, bool) {
	const (
		    = 5.00000000000000000000e-01
		 = 6.36619772367581382433e-01
		  = 1.57079632673412561417e+00
		 = 6.07710050650619224932e-11
		  = 6.07710050630396597660e-11
		 = 2.02226624879595063154e-21
		  = 2.02226624871116645580e-21
		 = 8.47842766036889956997e-32
	)
	 := [...]uint32{
		0x3ff921fb, 0x400921fb, 0x4012d97c, 0x401921fb, 0x401f6a7a, 0x4022d97c,
		0x4025fdbb, 0x402921fb, 0x402c463a, 0x402f6a7a, 0x4031475c, 0x4032d97c,
		0x40346b9c, 0x4035fdbb, 0x40378fdb, 0x403921fb, 0x403ab41b, 0x403c463a,
		0x403dd85a, 0x403f6a7a, 0x40407e4c, 0x4041475c, 0x4042106c, 0x4042d97c,
		0x4043a28c, 0x40446b9c, 0x404534ac, 0x4045fdbb, 0x4046c6cb, 0x40478fdb,
		0x404858eb, 0x404921fb,
	}
	 := highWord()
	 :=  & 0x7fffffff
	if  <= 0x3fe921fb {
		return 0, , 0, true
	}
	if  < 0x4002d97c {
		if int32() > 0 {
			 := jsSub(, )
			if  != 0x3ff921fb {
				 := jsSub(, )
				return 1, , jsSub(jsSub(, ), ), true
			}
			 = jsSub(, )
			 := jsSub(, )
			return 1, , jsSub(jsSub(, ), ), true
		}
		 := jsAdd(, )
		if  != 0x3ff921fb {
			 := jsAdd(, )
			return -1, , jsAdd(jsSub(, ), ), true
		}
		 = jsAdd(, )
		 := jsAdd(, )
		return -1, , jsAdd(jsSub(, ), ), true
	}
	if  > 0x413921fb {
		return 0, 0, 0, false
	}
	 := math.Abs()
	 := int32(jsAdd(jsMul(, ), ))
	 := float64()
	 := jsSub(, jsMul(, ))
	 := jsMul(, )
	 := 0.0
	if  < 32 &&  != [-1] {
		 = jsSub(, )
	} else {
		 := int( >> 20)
		 = jsSub(, )
		 := highWord()
		 :=  - int((>>20)&0x7ff)
		if  > 16 {
			 = 
			 = jsMul(, )
			 = jsSub(, )
			 = jsSub(jsMul(, ), jsSub(jsSub(, ), ))
			 = jsSub(, )
			 = highWord()
			 =  - int((>>20)&0x7ff)
			if  > 49 {
				 = 
				 = jsMul(, )
				 = jsSub(, )
				 = jsSub(jsMul(, ), jsSub(jsSub(, ), ))
				 = jsSub(, )
			}
		}
	}
	 := jsSub(jsSub(, ), )
	if int32() < 0 {
		return -, -, -, true
	}
	return , , , true
}

func jsKernelCos(,  float64) float64 {
	const (
		 = 1.00000000000000000000e+00
		  = 4.16666666666666019037e-02
		  = -1.38888888888741095749e-03
		  = 2.48015872894767294178e-05
		  = -2.75573143513906633035e-07
		  = 2.08757232129817482790e-09
		  = -1.13596475577881948265e-11
	)
	 := highWord() & 0x7fffffff
	if  < 0x3e400000 && int() == 0 {
		return 
	}
	 := jsMul(, )
	 := jsAdd(, jsMul(, ))
	 = jsAdd(, jsMul(, ))
	 = jsAdd(, jsMul(, ))
	 = jsAdd(, jsMul(, ))
	 = jsAdd(, jsMul(, ))
	 := jsMul(, )
	 := jsSub(jsMul(, ), jsMul(, ))
	if  < 0x3fd33333 {
		return jsSub(, jsSub(jsMul(.5, ), ))
	}
	 := .28125
	if  <= 0x3fe90000 {
		 = math.Float64frombits(uint64(-0x00200000) << 32)
	}
	 := jsSub(jsMul(.5, ), )
	 := jsSub(, )
	return jsSub(, jsSub(, ))
}

func jsKernelSin(,  float64,  bool) float64 {
	const (
		 = 5.00000000000000000000e-01
		   = -1.66666666666666324348e-01
		   = 8.33333333332248946124e-03
		   = -1.98412698298579493134e-04
		   = 2.75573137070700676789e-06
		   = -2.50507602534068634195e-08
		   = 1.58969099521155010221e-10
	)
	 := highWord() & 0x7fffffff
	if  < 0x3e400000 && int() == 0 {
		return 
	}
	// Keep these source-shaped expressions unbarriered. The official Node.js
	// 24.19.0 V8 builds contract them on arm64 but not x64, and that one-ULP
	// architecture difference is observable in Math.cos. Go reproduces the same
	// per-architecture results; forcing jsMul/jsAdd boundaries here would not.
	 :=  * 
	 :=  * 
	 :=  + *(+*(+*(+*)))
	if ! {
		return  + *(+*)
	}
	return  - ((*(*-*) - ) - *)
}

func highWord( float64) uint32 { return uint32(math.Float64bits() >> 32) }

// Go permits fused multiply-add across ordinary expression boundaries. These
// non-inline helpers preserve fdlibm's binary64 operation boundaries.
//
//go:noinline
func jsAdd(,  float64) float64 { return  +  }

//go:noinline
func jsSub(,  float64) float64 { return  -  }

//go:noinline
func jsMul(,  float64) float64 { return  *  }