divisible by到底是整除还是除尽的意思?整除和除尽在数学概念上还是不同的呢

用 Haskell 的整除调试 C - 技术翻译 - 开源中国社区
用 Haskell 的整除调试 C
【已翻译100%】
英文原文:
推荐于 9个月前 (共 13 段, 翻译完成于 11-06)
参与翻译&(3人)&: ,
好的类型系统涵盖了很多小的错误。单元测试、精心设计和健全的头脑可以让你通过更大的测试。但是,有时候,在大型代码库中的复杂错误需要重型调试工具。
这样一类的工具之一是&Delta Debugging&,它反复压减递归数据结构,以找到仍然复现该 bug 的最小测试集。如果你曾经使用过 git bisect 来查找大型代码库中的一个小小的破坏性改动,那么你将会非常欢迎该技术。
本文包括:
Delta 调试技术简介
实现一个通用的增量调试工具
使用 Haskell 的 FFI 来控制 C 象棋引擎
定位导致该棋牌引擎的错误的原因
&翻译得不错哦!
在,我用C实现了象棋引擎。我在其移动生成器中引入了一个错误。回想一下移动生成器涉及5个函数:
typedef&...&
typedef&...&
typedef&...&
//&Move&generation
iterator&mkIterator(gamestate&g);
iterator&advance_iterator(gamestate&g,&iterator&i);
gamestate&apply_move(gamestate&g,&move&m);
bool&is_iterator_finished(iterator&x);
move&dereference_iterator(iterator&i);
void&print_fen(gamestate&g,&char&*buffer);
gamestate&new_game();
//&The&actual&function&used&to&define&the&bug
uint64_t&perft(gamestate&g,&int&depth);
用于测试象棋引擎的“黄金标准”是将上述仿版功能的输出与进行比较。我们发现的错误从看板的开始状态很容易看到,所以new_game将是引擎中我所暴露的唯一的gamestate值。在FFI部分中,我将为所有内容定义Haskell封装器:
data&Gamestate
data&Iterator
newGame&&&&&&&&&&&&&::&Gamestate
printFen&&&&&&&&&&&&::&Gamestate&-&&String
mkIterator&&&&&&&&&&::&Gamestate&-&&Iterator
advanceIterator&&&&&::&Gamestate&-&&Iterator&-&&Iterator
perft&&&&&&&&&&&&&&&::&Gamestate&-&&Int32&&&&-&&Word64
applyMove&&&&&&&&&&&::&Gamestate&-&&Move&&&&&-&&Gamestate
isIteratorFinished&&::&Iterator&&-&&Bool
dereferenceIterator&::&Iterator&&-&&Move
为了检测错误,我们需要一个perft的参考版本来与我们的做对比。我会使用象棋做对比,所以我们的Haskell将会逐字地调用roce38进程,设置棋盘状态,并要求它计算一个perft值。
type&Move'&=&String
reference_perft&::&Gamestate&-&&Int32&-&&Word64
reference_moves&::&Gamestate&-&&[Move']
我已经使用unsafePerformIO的形式删除了对IO的约束,以简化文章的进度,但是最终的解决方案对于IO而言将是足够通用的。
&翻译得不错哦!
可简化的(Reducible)
以下是在的Arbitrary类型类的一个变体:
--&|&Gives&all&of&the&single-step&reductions&for&a&type.
--&|&It&is&recommended&to&put&the&largest&reductions&first.
class&Reducible&a&where
&&reductions&::&a&-&&[a]
minimize&::&Reducible&a&=&&(a&-&&Bool)&-&&a&-&&a
minimize&f&x&=&case&find&f&$&reductions&x&of
&&Nothing&-&&x
&&Just&y&-&&minimize&f&y
如果你有一个可以使web浏览器崩溃的HTML文件,minimize将删除标签或字符,直到它是一个最小的引起崩溃的文件。此变体将一次只删除单个标记或字符,而Arbitrary会出于性能考虑而移除整个批次。 回想一下,perft需要Gamestate和Depth值。 “最小可能”则意味着Depth是最小的。
instance&Reducible&Gamestate&where
&&reductions&::&Gamestate&-&&[Gamestate]
&&reductions&g&=
&&&&let&loop&i&=
&&&&&&&&&&if&isIteratorFinished&i
&&&&&&&&&&then&[]
&&&&&&&&&&else
&&&&&&&&&&&&let&m&=&dereferenceIterator&i
&&&&&&&&&&&&&&&&g'&=&applyMove&g&m
&&&&&&&&&&&&&&&&i'&=&advanceIterator&g&i
&&&&&&&&&&&&in&g'&:&loop&i'
&&&&in&loop&$&mkIterator&g
type&Depth&=&Int32
newtype&PerftTest&=&PerftTest&(Gamestate,&Depth)&deriving&(Show)
instance&Reducible&PerftTest&where
&&reductions&::&PerftTest&-&&[PerftTest]
&&reductions&(PerftTest&(g,&depth))&=
&&&&if&depth&==&1
&&&&then&[]
&&&&else&map&(\g'&-&&PerftTest&(g',&depth-1))&$&reductions&g
这里是如何应用此方法在两个不同引擎之间来找到具体位置的移动:
module&Main&where
import&Chess
import&Reducible
checkBug&::&PerftTest&-&&Bool
checkBug&(PerftTest&(g,&depth))&=
&&perft&g&depth&/=&reference_perft&g&depth
compareMoves&::&Gamestate&-&&([Move'],&[Move'])
compareMoves&g&=
&&let&lefts&=&map&printMove&$&moves&g
&&&&&&rights&=&reference_moves&g
&&in&(lefts&\\&rights,&rights&\\&lefts)
instance&Show&Gamestate&where
&&show&g&=&printFen&g
main&::&IO&()
&&let&g&=&newGame
&&&&&&i&=&mkIterator&g
&&let&(PerftTest&(g',&depth))&=&minimize&checkBug&$&PerftTest&(g,&3)
&&putStrLn&$&show&$&g'
&&putStrLn&$&show&$&compareMoves&g'
{-&Prints:
r1bqkbnr/pppppppp/n7/8/8/4P3/PPPP1PPP/RNBQKBNR&w&KQkq&-&0&1
([],["e1e2"])
FEN字符串可以直接粘贴到像XBoard这样的程序中,以方便位置的可视化,“e1e2”是Rocechess发出的而自身的引擎没有发出的动作。 在这一点上,你必须深入探究C语言中,看看为什么在e1的King是不被允许向北移动到e2的。我会通过展示我所做的改动来破坏它:
private&uint64_t&valid_king_moves(gamestate&g,&int&idx)
&&uint64_t&ret&=
&&&&bit(move_direction(idx,&DIRECTION_EAST))&|
&&&&bit(move_direction(idx,&DIRECTION_WEST))&|
&&&&//&bit(move_direction(idx,&DIRECTION_NORTH))&|
&&&&bit(move_direction(idx,&DIRECTION_SOUTH))&|
&&&&bit(move_direction(idx,&DIRECTION_NORTHEAST))&|
&&&&bit(move_direction(idx,&DIRECTION_SOUTHEAST))&|
&&&&bit(move_direction(idx,&DIRECTION_NORTHWEST))&|
&&&&bit(move_direction(idx,&DIRECTION_SOUTHWEST))
我在许多不同软件项目中的经验是,调试中的大部分工作是在创建一个小型的独立的测试用例来验证问题,而不是实际的修复。
&翻译得不错哦!
是我写这篇文章的主要原因,并且允许我们来
概括以上的
minimize。由于上下文是调试一个
国际象棋引擎,我将使用演绎逻辑的语言来描述我们将如何使用它。
这个想法是为了证明
perft g 6的价值是正确的,你需要两个组成部分:
perft g 6分解为子问题的方法
perft g' 5。
一种证明基本情况
用例的方法正确:
perft g 0 == 1
由于我们正在调试,这样的证明是不可能的,因为我们手头有一个失败的测试用例。但是,我们可以在上下文中定义“proof”是什么意思,因此我们将使用“正确的或者产生具体的最小反例”:
--&测试用例a可以分解成较小的小问题。
--&反例查找器扫描a并产生:
--&1.没有:A证明所有的子问题都是正确的
--&2.只是b:有些子问题是错误,相对与b来说
newtype&Cx&b&a&=&Cx&{&unCx&::&a&-&&Maybe&b&}
实际上有3种不同的类型,对应于3种不同的验证技术: &小节 概括了&。 &小节 概括了&。
&小节 概括了&。
&翻译得不错哦!
Contravariant
在大多数程序中,你可以从诸如文件或系统调用等可感知数据中获取的值开始,并应用函数将它们转换为更抽象或有用的信息。在调试时这个过程是相反的:我们从一个目标开始(一个失败的测试用例),并“反向”工作找到第一个有问题的地方。因此,Contravariant,Divisible 和 Decidable 的类型签名在前向思维方案中似乎是“不可能的”:
class&Contravariant&f&where
&&contramap&::&(a&-&&b)&-&&f&b&-&&f&a
在 proof 的上下文中,contramap 是一种将类型 a 的目标缩小到类型 b 的目标的方法:如果 f b 表示检测易错的 b 值的传感器,那么我们可以将其转换为监测易错的 a 值的传感器,通过将 a 值转换 b 值然后扫描 b 值。
一个目标通常会有类似 type Goal a = a -& Bool 的函数类型。首先,Contravariant 的不可能的签名背后的奥秘消失了,当你意识到我们并没有类型 a 或 b 时:我们只有一个函数,因此我们正在等待上游的代码向我们传递一个。
这是一个具体的实现:
instance&Contravariant&(Cx&b)&where
&&contramap&f&(Cx&g)&=&Cx&(g&.&f)
&翻译得不错哦!
contramap 让我们通过将其与更容易的目标相关联来完成另一个目标,然后完成更容易的目标。我们也可能想将目标分成多个简单的子目标:
class&Contravariant&f&=&&Divisible&f&where
&&divide&::&(a&-&&(b,&c))&-&&f&b&-&&f&c&-&&f&a
&&conquer&::&f&a
divide&足够合理了,但在 proof 的上下文中 conquer 似乎让我们证明了所有事情。divide 可以泛化到任意三元组上,同时 conquer 是一个空的连接:
divide4&::&Divisible&f&&&&&=&&(a&-&&(b,c,d,e))&-&&f&b&-&&f&c&-&&f&d&-&&f&e&-&&f&a
divide3&::&Divisible&f&&&&&=&&(a&-&&(b,c,d))&-&&f&b&-&&f&c&-&&f&d&-&&f&a
divide2&::&Divisible&f&&&&&=&&(a&-&&(b,c))&-&&f&b&-&&f&c&-&&f&a
divide1&::&Contravariant&f&=&&(a&-&&(b))&-&&f&b&-&&f&a
divide0&::&Divisible&f&&&&&=&&(a&-&&())&-&&f&a
divide0&_&=&conquer
divide1&=&contramap
divide2&=&divide
divide3&split3&pb&pc&pd&=
&&divide&(reassociate&.&split3)&pb&$
&&divide&id&pc&pd
&&&&reassociate&(x,y,z)&=&(x,(y,z))
divide4&split4&pb&pc&pd&pe&=
&&divide&(reassociate4&.&split4)&pb&$
&&divide3&id&pc&pd&pe
&&&&reassociate4&(x,y,z,w)&=&(x,(y,z,w))
通常,divide 包含一系列的子问题及针对这些子问题的解决方案,并且会把这些结合成一个方案以处理更大的问题。下面是三元组的示例,泛化到任意规模的链表:
divideList&::&Divisible&f&=&&[(a&-&&b,&f&b)]&-&&f&a
divideList&=&\case
&&[]&&&&&&&&&&&-&&conquer
&&((f,&px):xs)&-&&divide&(reproject&f)&px&(divideList&xs)
&&&&reproject&::&(a&-&&b)&-&&(a&-&&(b,a))
&&&&reproject&f&=&\x&-&&(f&x,&x)
上面的 divideList 并不是完成泛化的,因为它要求每个子问题必须是相同的类型。
conquer 是一个表示子问题不再需要继续检查的断言。回忆下,我们的 Cx 类型意味着“或者说有子问题都是对的,或者我们已经找到了怀疑的证据”。conquer 将会对应于这里的第一种情况。
下面是对于我们的 counterexample 检测器我们该如何实现 divide 的:
instance&Divisible&(Cx&b)&where
&&divide&split&(Cx&left)&(Cx&right)&=&Cx&$&\x&-&
&&&&let&(lProblem,&rProblem)&=&split&x
&&&&--&One&branch&must&produce&a&counterexample
&&&&in&case&(left&lProblem,&right&rProblem)&&of
&&&&&&(Just&x,&_)&-&&Just&x
&&&&&&(_,&Just&x)&-&&Just&x
&&&&&&(Nothing,&Nothing)&-&&Nothing
&&conquer&=&Cx&$&const&Nothing
既然为了保证父问题的清晰所有的子问题都必须是清晰,如果我们在左侧分支发现错误的话我们可以尽早返回。
&翻译得不错哦!
可判定的(Decidable)
contramap对应于逻辑上的,而divide对应于逻辑与。另一个主要工具是逻辑或,由choose提供。
class&Divisible&f&=&&Decidable&f&where
&&lose&&&::&(a&-&&Void)&-&&f&a
&&choose&::&(a&-&&Either&b&c)&-&&f&b&-&&f&c&-&&f&a
lose&是在你知道你所选择的一个分支是不可能的,但被要求提供证明时的占位符。 只有3种可能的实现:一个例外,使用未定义或荒谬。
使用undefined或定义的异常。
const conquer
不同于conquer的常量
我在contravariant包中没有看到任何第三种类型的例子,但是我设想它可以用来回写反向跟踪,类似于使用MonadPlus中的来。
在我们的上下文中choose意味着,如果你尝试在类型a的值中定位错误,则可以将其拆分为两个子问题之一,并且可以在两个子问题中找到错误,然后可以通过找出哪些子问题更适合a并重用该证据。这是实现:
instance&Decidable&(Cx&b)&where
&&lose&_&=&conquer
&&choose&split&left&right&=&Cx&$&\x&-&
&&&&--&Both&branches&must&produce&a&counterexample
&&&&case&split&x&of
&&&&&&Left&l&-&&unCx&left&l
&&&&&&Right&r&-&&unCx&right&r
Decidable和Divisible的主要区别是Decidable精确分支到子系统中的一个,而Divisible把所有子问题结合起来。
在我们继续探讨重新实现minimize之前,我实现了decideList来说明下Decidable在实际中是如何工作的。
decideList&::&forall&a&b&f.&Decidable&f&=&&(a&-&&(Integer,&b))&-&&[f&b]&-&&f&a
decideList&f&(xp:xps)&=&choose&caseConstructor&xp&(decideList&nextF&xps)
&&&&caseConstructor&::&a&-&&Either&b&a
&&&&caseConstructor&x&=
&&&&&&let&(c,&w)&=&f&x
&&&&&&in&case&c&of
&&&&&&&&0&-&&Left&w
&&&&&&&&n&-&&Right&x
&&&&nextF&::&a&-&&(Integer,&b)
&&&&nextF&x&=&let&(c,&w)&=&f&x
&&&&&&&&&&&&&&in&(c-1,&w)
这里的想法是(Integer, b)是由分支选择符和值b组成的。对于Either,Left将是分支0,而Rightt将是分支1.&caseConstructor或者选择当前分支,或者将a值传递到下一个线程。与divideList一样,decideList并不是完全通用的,因为它要求每个子问题都是相同的类型。
&翻译得不错哦!
我们开始泛化我们最初的minimize函数。这是其实现:
minimize&::&Reducible&a&=&&(a&-&&Bool)&-&&a&-&&a
minimize&f&x&=&case&find&f&$&reductions&x&of
&&Nothing&-&&x
&&Just&y&-&&minimize&f&y
我们用3步泛化它:
首先,我们的Cx类型包含一个 a&-&&Maybe a,可以同时表示minimize的a -& Bool和a -& a部分。因此minimize就变成了Reducible a =& Cx a a -& Cx a a。
其次,我已经将Cx泛化为Decidable f限制,使得其签名变为(Decidable f, Reducible a) =& f a -& f a。
第三,minimize调用了.。因此我将其泛化为findD :: Decidable f =& f a -& f [a]。
import&Data.List&(uncons)
import&Control.Arrow&((&&&))
minimizeD&::&(Decidable&f,&Reducible&a)&=&&f&a&-&&f&a
minimizeD&pred&=&divide&(reductions&&&&&id)&(findD&$&minimizeD&pred)&pred
findD&::&Decidable&f&=&&f&a&-&&f&[a]
findD&p&=&chooseMaybe&uncons&conquer&(divided&p&(findD&p))
chooseMaybe&::&Decidable&f&=&&(a&-&&Maybe&b)&-&&f&()&-&&f&b&-&&f&a
chooseMaybe&p&nothing&just&=&choose&(maybe&(Left&())&Right&.&p)&nothing&just
uncons&::&[a]&-&&Maybe&(a,&[a])
(&&&)&::&(a&-&&b)&-&&(a&-&&c)&-&&(a&-&&(b,c))
在我们特定的上下文上,下面是你可能如何在英语中理解它的描述:
minimizeD: minimal错误或是来自当前节点的reductions之一,或是来自当前节点本身(id)。
findD: minimal错误或因为列表为空(conquer)、当前元素(p)或列表中的剩余值(findD p)而变得不存在的。
下面是一个使用简单类型的函数,可以被简单地应用:
minimizeD''&::&PerftTest&-&&Maybe&PerftTest
minimizeD''&x&=&unCx&(minimizeD&(Cx&$&liftPred&checkBug))&x
&&&&liftPred&::&(a&-&&Bool)&-&&(a&-&&Maybe&a)
&&&&liftPred&pred&=&\x&-&
&&&&&&if&pred&x
&&&&&&then&Just&x
&&&&&&else&Nothing
testCase&::&Int&-&&PerftTest
testCase&n&=&PerftTest&(newGame,&n)
exampleInvocation&=&minimizeD''&$&testCase&3
&翻译得不错哦!
我在 C 象棋引擎中编写 FFI 的其中一个原因是为了证明我所主推的术语和类型类不仅仅是抽象的废话,而是具有实际的计算意义的。没有人会批判 C 语言过于抽象,所以我觉得它会给 minimizeD 的控制代码提供一个很好的平衡。
回想一下,pred 在每次调用时都会实例化一个单独的系统进程。好的解决方案似乎应该尽可能少地创建子进程。即使忽略了我对 unsafePerformIO 的使用,一个很好的解决方案应该避免过度地递归或者不必要地调用开销大的函数。
我添加一个全局计数器,在我们每次创建一个 Rocechess 进程时都会自加。我会使用该计数器来检测任何隐藏的性能问题。
import&Data.IORef
counter&=&unsafePerformIO&$&newIORef&0
tickCounter&::&IO&()
tickCounter&=&modifyIORef'&counter&(+1)
timeTicks&::&Show&a&=&&a&-&&IO&Int
timeTicks&x&=&do
&&ticks&&-&readIORef&counter
&&putStrLn&$&show&x
&&ticks'&&-&readIORef&counter
&&return&$&ticks'&-&ticks
timeTicks 会将输入强制打印为输出,并在前后比较计数器的值。下面是使用最初的 minimize 的输出结果:
timeTicks&$&minimize&checkBug&$&testCase&3
--&PerftTest&(r1bqkbnr/pppppppp/n7/8/8/4P3/PPPP1PPP/RNBQKBNR&w&KQkq&-&0&1,1)
因此总共有 14个 进程被创建用于计算 perft 值,以找到最小测试集。那么我们的 slick one-liner 进展如何呢?
timeTicks&$&minimizeD''&$&testCase&3
--&Just&(PerftTest&(r1bqkbnr/pppppppp/n7/8/8/4P3/PPPP1PPP/RNBQKBNR&w&KQkq&-&0&1,1))
在查找同样的游戏失败位置时,泛化后的算法比我们简单版算法速度提升了18倍。
&翻译得不错哦!
为了解决这个问题,我将首先分析这个问题,然后引入一个新的类型类 Refinable 来解决它。
我们并列地比较下这两个:
minimizeD&::&(Decidable&f,&Reducible&a)&=&&f&a&-&&f&a
minimizeD&pred&=&divide&(reductions&&&&&id)&(findD&$&minimizeD&pred)&pred
minimize&::&Reducible&a&=&&(a&-&&Bool)&-&&a&-&&a
minimize&f&x&=&case&find&f&$&reductions&x&of
&&Nothing&-&&x
&&Just&y&-&&minimize&f&y
请注意,minimize 通过 reduction 触发在每个元素上调用 f ,而 minimizeD 调用了 minimizeD pred 。在 minimize 中,如果节点被评估为 Nothing ,其中没有递归,因为我们知道所有的子问题都是正确的。
我们可以通过只传递 pred 到 findD 来停止递归:
minimizeD&::&(Decidable&f,&Reducible&a)&=&&f&a&-&&f&a
minimizeD&pred&=&divide&(reductions&&&&&id)&(findD&$&pred)&pred
但是现在反例是仅有1步的、并且不是最小的反例。
我们需要做的是完善失败案用例。首先,我们运行 pred 来扫描父节点中的一个元素(一个粗粒度的失败用例),然后我们运行 minimizeD pred 来缩减它,一旦我们确认它存在(一个很好的失败用例)。
以下是如何实现的:
class&Divisible&f&=&&Refinable&f&where
&&implies&::&f&a&-&&f&a&-&&f&a
instance&Refinable&(Cx&b)&where
&&implies&l&r&=&Cx&$&\x&-&
&&&&case&unCx&l&x&of
&&&&&&Nothing&-&&Nothing
&&&&&&Just&_&-&&unCx&r&x
正如 divide 允许我们在找到反例时立即终止 proof 一样,implies 允许我们证实找不到反例存在时可以立即终止 proof :
implies&conquer&x&=&conquer
divide&delta&conquer&x&=&x
divide&delta&x&conquer&=&x
delta&x&=&(x,x)
所有的优化都在这里使用了:第一个是在 findD 中,当我们找到一个元素时终止搜索,第二我们将显式添加:
minimizeD&::&(Refinable&f,&Decidable&f,&Reducible&a)&=&&f&a&-&&f&a
minimizeD&pred&=&divide&(reductions&&&&&id)&(findD&checkChild)&pred
&&&&checkChild&=&pred&`implies`&minimizeD&pred
现在这个数目基本上是相等的了:
PerftTest&(r1bqkbnr/pppppppp/n7/8/8/4P3/PPPP1PPP/RNBQKBNR&w&KQkq&-&0&1,1)
*Main&&timeTicks&$&minimizeD''&$&testCase&3
Just&(PerftTest&(r1bqkbnr/pppppppp/n7/8/8/4P3/PPPP1PPP/RNBQKBNR&w&KQkq&-&0&1,1))
额外的节点是因为 minimizeD 扫描了根节点,与此同时 minimize 会立即递归进去。这样,我们就在无意中修复了 minimize 中的轻微的不一致性。
&翻译得不错哦!
我们的翻译工作遵照 ,如果我们的工作有侵犯到您的权益,请及时联系我们
暂无网友评论基本性质/整除
整除抽象图①若a|b,a|c,则a|(b±c)。
②若a|b,则对c,a|bc。
③对任意非零整数a,±1|a,±a|a。④若a|b,b|a,则|a|=|b|。
⑤如果a能被b整除,c是任意,那么积ac也能被b整除。
⑥如果a同时被b与c整除,并且b与c互质,那么a一定能被积bc整除,反过来也成立。对任意整数a,b,b&0,存在唯一的数对q,r,使a=bq+r,其中0≤r
若c|a,c|b,则称c是a,b的公因数。若d是a,b的公因数,d≥0,且d可被a,b的任意公因数整除,则d是a,b的最大公因数。若a,b的最大公因数等于1,则称a,b互素,也称互质。累次利用带余除法可以求出a,b的最大公因数,这种方法常称为辗转相除法。又称欧几里得算法。
数的特征/整除
常用辨别方法(1)1与0的特性:
1是任何整数的,即对于任何整数a,总有1|a.
0是任何非零整数的倍数,a≠0,a为整数,则a|0.
(2)能被2整除的数的若一个整数的末位是0、2、4、6或8,则这个数能被2整除。(3)能被3整除的数的特征1,若一个整数的数字和能被3整除,则这个整数能被3整除。2,由相同的数字组成的三位数、六位数、九位数……这些数字能被3整除。如111令3整除。(4)能被4整除的数的特征若一个整数的末尾两位数能被4整除,则这个数能被4整除。(5)能被5整除的数的特征若一个整数的末位是0或5,则这个数能被5整除。(6)能被6整除的数的特征若一个整数能被2和3整除,则这个数能被6整除。(7)能被7整除的数的特征
若一个整数的个位数字截去,再从余下的数中,减去个位数的2倍,如果差是7的倍数,则原数能被7整除。如果差太大或心算不易看出是否7的倍数,就需要继续上述「截尾、倍大、相减、验差」的过程,直到能清楚判断为止。同能被17整除的数的特征。
(8)能被8整除的数的特征若一个整数的末尾三位数能被8整除,则这个数能被8整除。(9)能被9整除的数的特征若一个整数的数字和能被9整除,则这个整数能被9整除。(10)能被10整除的数的特征若一个整数的末位是0,则这个数能被10整除。(11)能被11整除的数的特征
若一个整数的奇位数字之和与偶位数字之和的差能被11整除,则这个数能被11整除。11的倍数检验法也可用上述检查7的「割尾法」处理!过程唯一不同的是:倍数不是2而是1!
(12)能被12整除的数的特征若一个整数能被3和4整除,则这个数能被12整除。其他辨别方法(13)能被13整除的数的特征
若一个整数的个位数字截去,再从余下的数中,加上个位数的4倍,如果和是13的倍数,则原数能被13整除。如果和太大或心算不易看出是否13的,就需要继续上述「截尾、倍大、相加、验和」的过程,直到能清楚判断为止。
(14)能被17整除的数的特征
1、若一个整数的个位数字截去,再从余下的数中,减去个位数的5倍,如果差是17的倍数,则原数能被17整除。如果差太大或心算不易看出是否17的倍数,同能被7整除的特征一样。
2、若一个整数的末三位与3倍的前面的隔出数的差能被17整除,则这个数能被17整除。(15)能被19整除的数的特征
1、若一个整数的个位截去,再从余下的数中,加上个位数的2倍,如果和是19的倍数,则原数能被19整除。如果和太大或心算不易看出是否19的倍数,就需要继续使用能被13整除特征的方法。
2、若一个整数的末三位与7倍的前面的隔出数的差能被19整除,则这个数能被19整除。(16)能被23整除的数的特征若一个整数的末四位与前面5倍的隔出数的差能被23(或29)整除,则这个数能被23整除。统一方法
设整数x的数为a,判断其是否能被n整除:令(x-a)/10-ma=nk(k∈N*),则x=n[10k+(10m+1)a/n],要使x能被n整除,只要(10m+1)/n为自然数。
整除第七条(7):把个位截去,再从余下的数中,减去个位数的2倍,差是7的倍数,则原数能被7整除。
例:①147,截去个位数字后为14,用14-7*2=0,0是7的倍数,所以147也是7的倍数。
②2198,截去个位数字后为219,用219-8*2=203;继续下去,截去个位数字后为20,用20-3*2=14,14是7的倍数,所以2198也是7的倍数。
设p=a1+a2*10+a3*10^2+...+a(n-1)*10^(n-1)+an*10^nq=a2+a3*10+...+a(n-1)*10^(n-2)+an*10^(n-1)-2a12p+q=21(a2+a3*10+...+an*10^(n-1))又因为21=7*3,所以若p是7的倍数,那么可以得到q是7的。
万方数据期刊论文
四川大学学报(自然科学版)
万方数据期刊论文
四川大学学报(自然科学版)
万方数据期刊论文
华中师范大学学报(自然科学版)
&|&相关影像
互动百科的词条(含所附图片)系由网友上传,如果涉嫌侵权,请与客服联系,我们将按照法律之相关规定及时进行处理。未经许可,禁止商业网站等复制、抓取本站内容;合理使用者,请注明来源于www.baike.com。
登录后使用互动百科的服务,将会得到个性化的提示和帮助,还有机会和专业认证智愿者沟通。
此词条还可添加&
编辑次数:18次
参与编辑人数:12位
最近更新时间: 11:25:24
贡献光荣榜
扫码下载APP{{{{{{一个判断能否整除的程序}}}}}}}}【vb吧】_百度贴吧
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&签到排名:今日本吧第个签到,本吧因你更精彩,明天继续来努力!
本吧签到人数:0成为超级会员,使用一键签到本月漏签0次!成为超级会员,赠送8张补签卡连续签到:天&&累计签到:天超级会员单次开通12个月以上,赠送连续签到卡3张
关注:109,465贴子:
{{{{{{一个判断能否整除的程序}}}}}}}}收藏
有没有大神帮忙下?界面就是三个textbox一个按钮,前两个框输数字,底下的框输出结果,结果例如:10可以被5整除要求用一个function isDivisibleby还有mod(余数)还有一个print的步骤新手初学完全不懂怎么把几个步骤联系起来。。。有没有大神能写个示例啊?谢谢
通用软件不合适,定做软件太昂贵,自己用vb.net开发太难,何不试试FoxTable?
ps. 语言是vb.net
mod看是不是为0。。。。
vb.net没有print函数。。。。。
Public Class frmCheckDivisability
Private Sub btnCheck_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnCheck.Click
Dim x, y As Integer
x = txtDividend.Text
y = txtDivisor.Text
Function isDivisibleBy(ByVal x As Integer, ByVal y As Integer) As Boolean
If (x Mod y) = 0 Then
isDivisibleBy = True
isDivisibleBy = False
Return isDivisibleBy
End Function
Private Sub printDivisability(ByVal x As Integer, ByVal y As Integer)
Debug.Print(x, y)
End SubEnd Class
Public Class frmCheckDivisabilityPrivate Sub btnCheck_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnCheck.Click
Dim x, y As Integer
x = txtDividend.Text
y = txtDivisor.Text
ReturnEnd Sub
Function isDivisibleBy(ByVal x As Integer, ByVal y As Integer) As Boolean
If (x Mod y) = 0 Then
isDivisibleBy = True
isDivisibleBy = False
End IfReturn isDivisibleBy
End FunctionPrivate Sub printDivisability(ByVal x As Integer, ByVal y As Integer)
Debug.Print(x, y)
End SubEnd Class
直接用if判断mod的结果是不是0,是0的话就能整除了
Dim x, y As Integer x = int(txtDividend.Text) y = int(txtDivisor.Text)if x mod y = 0 then
msgbox"能整除"else
msgbox"不能整除"end if
登录百度帐号

我要回帖

更多关于 evenly divisible 的文章

 

随机推荐