我整个星期都在为编码平台解决此问题的方法而苦苦挣扎。目前,这并不是要在那儿获得积分,而是要更多地了解我在解决方案/推理中的错误之处。
这是作业:
步行者从O点开始,沿着OA,AB和BC步行。当他是 在C中(C将在上半平面中),距离CO是多少? tOC的正角度,分钟,秒是多少?
角度tOA为alpha(此处为45度),角度hAB为beta(此处为30) 度),uBC角为伽马(此处为60度)。
带有参数的任务函数solve(a,b,c,alpha,beta,gamma)
a,b,c:以距离alpha,beta,gamma为单位的正整数: 以度为单位的正整数(正角为逆时针方向) 返回一个数组
第一个元素:距离CO(四舍五入到最接近的整数),然后是角度 tOC具有以下三个元素:数组的第二个元素: 角度tOC的度数(正整数) 数组的元素:角度tOC中的分钟数(截断了) 正整数)数组的第四个元素:秒数 tOC角(截断正整数)
基本上每个步骤都会创建一个矩形三角形。我的方法是使用正弦规则逐步找到A,B和C的坐标,然后轻松找到CO和角度COt。根据测试,我得到了正确的CO段,但是角度似乎是错误的:
Test Failed
Expected Array(15, 135, 49, 18), but got Array(15, 143, 2, 45)
和
Test Failed
Expected Array(20, 141, 4, 23), but got Array(20, 139, 51, 47)
下面,我粘贴解决方案,该站点提供了测试用例:
object Walker {
case class Point(x: Double, y: Double){
def moveLeft(by: Double) = Point(by - x, y)
def moveRight(by: Double) = Point(by + x, y)
def moveUp(by: Double) = Point(x, by + y)
def moveDown(by: Double) = Point(x, by - y)
def inverse() = Point(y, x)
}
implicit def roundUp(d: Double): Int = math.ceil(d).toInt
def solve(a: Int, b: Int, c: Int, alpha: Int, beta: Int, gamma: Int): Array[Int] = {
val pointA = pointHypotenuse(a, alpha)
val pointB = pointHypotenuse(b, beta).inverse().moveLeft(pointA.x).moveUp(pointA.y)
val pointC = pointHypotenuse(c, gamma).moveLeft(pointB.x).moveDown(pointB.y)
val coHypotenuse: Int = math.sqrt(math.pow(pointC.x, 2) + math.pow(pointC.y, 2))
val sinC = math.sin(math.abs(pointC.x)/coHypotenuse)
val tOC = 180 - sinC.toDegrees
coHypotenuse +: degrees(tOC)
}
def pointHypotenuse(coteHypotenuse: Int, angleHypotenuse: Int): Point = {
val sinDuAngle = math.sin(math.toRadians(angleHypotenuse))
val coteOppose = sinDuAngle * coteHypotenuse
Point(math.sqrt(math.pow(coteHypotenuse, 2) - math.pow(coteOppose, 2)), coteOppose)
}
def degrees(deg: Double): Array[Int] = {
Stream.iterate((deg.toInt, deg - deg.toInt)){
case (_, r) =>
val by60 = r*60
(by60.toInt, by60 - by60.toInt)
}.map(_._1).take(3).toArray
}
}
测试(来自平台):
class WalkerTest extends FlatSpec {
it should "pass basic tests" in {
dotest(12, 20, 18, 45, 30, 60, Array(15, 135, 49, 18))
dotest(15,15,19,50,29,55, Array(12, 133, 18, 44))
dotest(14,25,17,41,35,59, Array(20, 129, 41, 57))
}
}
object WalkerTest {
private def dotest(a: Int, b: Int, c: Int, aa: Int, bb: Int, cc: Int, expect: Array[Int]): Unit = {
val actual: Array[Int] = Walker.solve(a, b, c, aa, bb, cc)
assertResult(expect){actual}
}
}
我不认为这是一个舍入错误(由断言导致所有Doubles乘以Ints距离替换)。我通常不会问这个,但是我似乎对此确实很受阻。
答案 0 :(得分:1)
行
val sinC = math.sin(math.abs(pointC.x)/coHypotenuse)
得到某个段比率的正弦,但是这个比率是余弦。
要获得一个角度,应该使用arccos
答案 1 :(得分:0)
您必须传递beta(90+given)
和gamma(180+given)
的角度,因为所有角度都将从positive x-axis
沿逆时针方向传递。然后,似乎不需要moveLeft,moveRight,moveUp,moveDown
和inverse
函数。代替所有它们,您只能在案例类moveTo(p:Point)
中使用一个函数Point
,并且此修改可以提供准确的测试结果,如下面的scala REPL所示:
object Walker {
case class Point(x: Double, y: Double){
def moveTo(p:Point) = {val t = this.x+p.x;val t1 = this.y+p.y;Point(t,t1) }
}
def solve(a: Double, b: Double, c: Double, alpha: Double, beta: Double, gamma: Double):Array[Int]= {
val pointA = movedPoint(a, alpha)
val pointB = pointA.moveTo(movedPoint(b,beta))
val pointC = pointB.moveTo(movedPoint(c,gamma))
val co = math.sqrt( math.pow(pointC.x, 2) + math.pow(pointC.y, 2))
val angletOC = Math.asin(math.abs(pointC.y)/co).toDegrees
val tOC = if(pointC.x<=0 && pointC.y>=0)
180 - angletOC
else if(pointC.x<=0 && pointC.y<=0)
180 + angletOC
else if(pointC.x>0 && pointC.y<0)
270 + angletOC
else angletOC
Math.round(co).toInt +: convDegMinSec(tOC)
}
def movedPoint(dist:Double,angle:Double):Point = {
val yCo = dist*Math.sin(Math.toRadians(angle))
val xCo = dist*Math.cos(Math.toRadians(angle))
Point(xCo,yCo)
}
def convDegMinSec(deg: Double): Array[Int] = {
val degs = deg.toInt
val mins = (deg - deg.toInt)*60
val secs = (mins-mins.toInt)*60
val arr = Array(degs,mins.toInt,secs.toInt)
arr
}
}
在Scala REPL中:
scala> Walker.solve(12,20,18,45,90+30,180+60)
res58: Array[Int] = Array(15, 135, 49, 18)
scala> Walker.solve(15,15,19,50,90+29,180+55)
res59: Array[Int] = Array(12, 133, 18, 44)
scala> Walker.solve(14,25,17,41,90+35,180+59)
res60: Array[Int] = Array(20, 129, 41, 57)